Ejemplo n.º 1
0
def rayleigh_scattering_spectrum ():
    '''Get the Rayleigh scattering spectrum (independent of illuminant), as a numpy array.'''
    spectrum = ciexyz.empty_spectrum()
    num_wl = spectrum.shape[0]
    for i in range (0, num_wl):
        spectrum [i][1] = rayleigh_scattering (spectrum [i][0])
    return spectrum
Ejemplo n.º 2
0
def rayleigh_scattering_spectrum():
    '''Get the Rayleigh scattering spectrum (independent of illuminant), as a numpy array.'''
    spectrum = ciexyz.empty_spectrum()
    (num_rows, num_cols) = spectrum.shape
    for i in xrange(0, num_rows):
        spectrum[i][1] = rayleigh_scattering(spectrum[i][0])
    return spectrum
Ejemplo n.º 3
0
 def reflection_spectrum (self):
     '''Get the reflection spectrum (independent of illuminant) for the thin film.'''
     spectrum = ciexyz.empty_spectrum()
     num_wl = spectrum.shape[0]
     for i in range (0, num_wl):
         wl_nm = spectrum [i][0]
         spectrum [i][1] = self.get_interference_reflection_coefficient (wl_nm)
     return spectrum
Ejemplo n.º 4
0
 def test_coverage_2(self, verbose=False):
     ''' Another coverage test. '''
     empty = ciexyz.empty_spectrum ()
     xyz = ciexyz.xyz_from_spectrum (empty)
     if verbose:
         print ('black = %s' % (str (xyz)))
     xyz_555 = ciexyz.xyz_from_wavelength (555.0)
     if verbose:
         print ('555 nm = %s' % (str (xyz_555)))
Ejemplo n.º 5
0
 def test_coverage_2(self, verbose=False):
     ''' Another coverage test. '''
     empty = ciexyz.empty_spectrum()
     xyz = ciexyz.xyz_from_spectrum(empty)
     if verbose:
         print('black = %s' % (str(xyz)))
     xyz_555 = ciexyz.xyz_from_wavelength(555.0)
     if verbose:
         print('555 nm = %s' % (str(xyz_555)))
Ejemplo n.º 6
0
def blackbody_spectrum(T_K):
    '''Get the spectrum of a blackbody, as a numpy array.'''
    spectrum = ciexyz.empty_spectrum()
    (num_rows, num_cols) = spectrum.shape
    for i in xrange(0, num_rows):
        specific_intensity = blackbody_specific_intensity(spectrum[i][0], T_K)
        # scale by size of wavelength interval
        spectrum[i][1] = specific_intensity * ciexyz.delta_wl_nm * 1.0e-9
    return spectrum
Ejemplo n.º 7
0
def blackbody_spectrum (T_K):
    '''Get the spectrum of a blackbody, as a numpy array.'''
    spectrum = ciexyz.empty_spectrum()
    (num_rows, num_cols) = spectrum.shape
    for i in xrange (0, num_rows):
        specific_intensity = blackbody_specific_intensity (spectrum [i][0], T_K)
        # scale by size of wavelength interval
        spectrum [i][1] = specific_intensity * ciexyz.delta_wl_nm * 1.0e-9
    return spectrum
Ejemplo n.º 8
0
 def reflection_spectrum(self):
     '''Get the reflection spectrum (independent of illuminant) for the thin film.'''
     spectrum = ciexyz.empty_spectrum()
     (num_rows, num_cols) = spectrum.shape
     for i in xrange(0, num_rows):
         wl_nm = spectrum[i][0]
         spectrum[i][1] = self.get_interference_reflection_coefficient(
             wl_nm)
     return spectrum
Ejemplo n.º 9
0
def blackbody_spectrum (T_K):
    '''Get the spectrum of a blackbody, as a numpy array.'''
    spectrum = ciexyz.empty_spectrum()
    num_wl = spectrum.shape[0]
    for i in range (0, num_wl):
        # Intensity per unit wavelength.
        specific_intensity = blackbody_specific_intensity (spectrum [i][0], T_K)
        # Scale by size of wavelength interval.
        spectrum [i][1] = specific_intensity * ciexyz.delta_wl_nm * 1.0e-9
    return spectrum
Ejemplo n.º 10
0
def blackbody_spectrum(T_K):
    '''Get the spectrum of a blackbody, as a numpy array.'''
    spectrum = ciexyz.empty_spectrum()
    num_wl = spectrum.shape[0]
    for i in range(0, num_wl):
        # Intensity per unit wavelength.
        specific_intensity = blackbody_specific_intensity(spectrum[i][0], T_K)
        # Scale by size of wavelength interval.
        spectrum[i][1] = specific_intensity * ciexyz.delta_wl_nm * 1.0e-9
    return spectrum
Ejemplo n.º 11
0
def get_constant_illuminant():
    '''Get an illuminant, with spectrum constant over wavelength, normalized to Y = 1.0.'''
    illuminant = ciexyz.empty_spectrum()
    (num_wl, num_cols) = illuminant.shape
    for i in range(0, num_wl):
        illuminant[i][1] = 1.0
    xyz = ciexyz.xyz_from_spectrum(illuminant)
    if xyz[1] != 0.0:
        scaling = 1.0 / xyz[1]
        illuminant[:, 1] *= scaling
    return illuminant
Ejemplo n.º 12
0
def get_constant_illuminant ():
    '''Get an illuminant, with spectrum constant over wavelength, normalized to Y = 1.0.'''
    illuminant = ciexyz.empty_spectrum()
    (num_wl, num_cols) = illuminant.shape
    for i in xrange (0, num_wl):
        illuminant [i][1] = 1.0
    xyz = ciexyz.xyz_from_spectrum (illuminant)
    if xyz [1] != 0.0:
        scaling = 1.0 / xyz [1]
        illuminant [:,1] *= scaling
    return illuminant
Ejemplo n.º 13
0
def cie_matching_functions_plot():
    '''Plot the CIE XYZ matching functions, as three spectral subplots.'''
    # get 'spectra' for x,y,z matching functions
    spectrum_x = ciexyz.empty_spectrum()
    spectrum_y = ciexyz.empty_spectrum()
    spectrum_z = ciexyz.empty_spectrum()
    (num_wl, num_cols) = spectrum_x.shape
    for i in xrange(0, num_wl):
        wl_nm = spectrum_x[i][0]
        xyz = ciexyz.xyz_from_wavelength(wl_nm)
        spectrum_x[i][1] = xyz[0]
        spectrum_y[i][1] = xyz[1]
        spectrum_z[i][1] = xyz[2]
    # Plot three separate subplots, with CIE X in the first, CIE Y in the second, and CIE Z in the third.
    # Label appropriately for the whole plot.
    pylab.clf()
    # X
    pylab.subplot(3, 1, 1)
    pylab.title('1931 CIE XYZ Matching Functions')
    pylab.ylabel('CIE $X$')
    spectrum_subplot(spectrum_x)
    tighten_x_axis(spectrum_x[:, 0])
    # Y
    pylab.subplot(3, 1, 2)
    pylab.ylabel('CIE $Y$')
    spectrum_subplot(spectrum_y)
    tighten_x_axis(spectrum_x[:, 0])
    # Z
    pylab.subplot(3, 1, 3)
    pylab.xlabel('Wavelength (nm)')
    pylab.ylabel('CIE $Z$')
    spectrum_subplot(spectrum_z)
    tighten_x_axis(spectrum_x[:, 0])
    # done
    filename = 'CIEXYZ_Matching'
    print 'Saving plot %s' % str(filename)
    pylab.savefig(filename)
Ejemplo n.º 14
0
def cie_matching_functions_plot ():
    '''Plot the CIE XYZ matching functions, as three spectral subplots.'''
    # get 'spectra' for x,y,z matching functions
    spectrum_x = ciexyz.empty_spectrum()
    spectrum_y = ciexyz.empty_spectrum()
    spectrum_z = ciexyz.empty_spectrum()
    (num_wl, num_cols) = spectrum_x.shape
    for i in xrange (0, num_wl):
        wl_nm = spectrum_x [i][0]
        xyz = ciexyz.xyz_from_wavelength (wl_nm)
        spectrum_x [i][1] = xyz [0]
        spectrum_y [i][1] = xyz [1]
        spectrum_z [i][1] = xyz [2]
    # Plot three separate subplots, with CIE X in the first, CIE Y in the second, and CIE Z in the third.
    # Label appropriately for the whole plot.
    pylab.clf ()
    # X
    pylab.subplot (3,1,1)
    pylab.title ('1931 CIE XYZ Matching Functions')
    pylab.ylabel ('CIE $X$')
    spectrum_subplot (spectrum_x)
    tighten_x_axis (spectrum_x [:,0])
    # Y
    pylab.subplot (3,1,2)
    pylab.ylabel ('CIE $Y$')
    spectrum_subplot (spectrum_y)
    tighten_x_axis (spectrum_x [:,0])
    # Z
    pylab.subplot (3,1,3)
    pylab.xlabel ('Wavelength (nm)')
    pylab.ylabel ('CIE $Z$')
    spectrum_subplot (spectrum_z)
    tighten_x_axis (spectrum_x [:,0])
    # done
    filename = 'CIEXYZ_Matching'
    print 'Saving plot %s' % str (filename)
    pylab.savefig (filename)
Ejemplo n.º 15
0
def test(verbose=0):
    '''Test the CIE XYZ conversions.  Mainly call some functions.'''
    for i in range(0, 100):
        wl_nm = 1000.0 * random.random()
        xyz = ciexyz.xyz_from_wavelength(wl_nm)
        if verbose >= 1:
            print('wl_nm = %g, xyz = %s' % (wl_nm, str(xyz)))
    for i in range(0, 10):
        empty = ciexyz.empty_spectrum()
        xyz = ciexyz.xyz_from_spectrum(empty)
        if verbose >= 1:
            print('black = %s' % str(xyz))
        xyz_555 = ciexyz.xyz_from_wavelength(555.0)
        if verbose >= 1:
            print('555 nm = %s' % str(xyz_555))
    print('test_ciexyz.test() passed.')
Ejemplo n.º 16
0
def init():
    '''Initialize CIE Illuminant D65.  This runs on module startup.'''
    first_wl = _Illuminant_D65_table[0][0]
    # for now, only consider the part in the normal visible range (360-830 nm)
    first_index = ciexyz.start_wl_nm - first_wl
    table_first = _Illuminant_D65_table[first_index][0]
    assert (table_first == 360), 'Mismatch finding 360 nm entry in D65 table'
    global _Illuminant_D65
    _Illuminant_D65 = ciexyz.empty_spectrum()
    (num_wl, num_cols) = _Illuminant_D65.shape
    for i in range(0, num_wl):
        _Illuminant_D65[i][1] = _Illuminant_D65_table[first_index + i][1]
    # normalization - illuminant is scaled so that Y = 1.0
    xyz = ciexyz.xyz_from_spectrum(_Illuminant_D65)
    scaling = 1.0 / xyz[1]
    _Illuminant_D65[:, 1] *= scaling
Ejemplo n.º 17
0
def init():
    """Initialize CIE Illuminant D65.  This runs on module startup."""
    first_wl = _Illuminant_D65_table[0][0]
    # for now, only consider the part in the normal visible range (360-830 nm)
    first_index = ciexyz.start_wl_nm - first_wl
    table_first = _Illuminant_D65_table[first_index][0]
    assert table_first == 360, "Mismatch finding 360 nm entry in D65 table"
    global _Illuminant_D65
    _Illuminant_D65 = ciexyz.empty_spectrum()
    (num_wl, num_cols) = _Illuminant_D65.shape
    for i in range(0, num_wl):
        _Illuminant_D65[i][1] = _Illuminant_D65_table[first_index + i][1]
    # normalization - illuminant is scaled so that Y = 1.0
    xyz = ciexyz.xyz_from_spectrum(_Illuminant_D65)
    scaling = 1.0 / xyz[1]
    _Illuminant_D65[:, 1] *= scaling
Ejemplo n.º 18
0
def test (verbose=0):
    '''Test the CIE XYZ conversions.  Mainly call some functions.'''
    for i in xrange (0, 100):
        wl_nm = 1000.0 * random.random()
        xyz = ciexyz.xyz_from_wavelength (wl_nm)
        if verbose >= 1:
            print 'wl_nm = %g, xyz = %s' % (wl_nm, str (xyz))
    for i in xrange (0, 10):
        empty = ciexyz.empty_spectrum ()
        xyz = ciexyz.xyz_from_spectrum (empty)
        if verbose >= 1:
            print 'black = %s' % (str (xyz))
        xyz_555 = ciexyz.xyz_from_wavelength (555.0)
        if verbose >= 1:
            print '555 nm = %s' % (str (xyz_555))
    print 'test_ciexyz.test() passed.'
Ejemplo n.º 19
0
def scattered_visual_brightness ():
    '''Plot the perceptual brightness of Rayleigh scattered light.'''
    # get 'spectra' for y matching functions and multiply by 1/wl^4
    spectrum_y = ciexyz.empty_spectrum()
    (num_wl, num_cols) = spectrum_y.shape
    for i in range (0, num_wl):
        wl_nm = spectrum_y [i][0]
        rayleigh = math.pow (550.0 / wl_nm, 4)
        xyz = ciexyz.xyz_from_wavelength (wl_nm)
        spectrum_y [i][1] = xyz [1] * rayleigh
    pylab.clf ()
    pylab.title ('Perceptual Brightness of Rayleigh Scattered Light')
    pylab.xlabel ('Wavelength (nm)')
    pylab.ylabel ('CIE $Y$ / $\lambda^4$')
    spectrum_subplot (spectrum_y)
    tighten_x_axis (spectrum_y [:,0])
    # done
    filename = 'Visual_scattering'
    print ('Saving plot %s' % str (filename))
    pylab.savefig (filename)
Ejemplo n.º 20
0
def scattered_visual_brightness():
    '''Plot the perceptual brightness of Rayleigh scattered light.'''
    # get 'spectra' for y matching functions and multiply by 1/wl^4
    spectrum_y = ciexyz.empty_spectrum()
    (num_wl, num_cols) = spectrum_y.shape
    for i in range(0, num_wl):
        wl_nm = spectrum_y[i][0]
        rayleigh = math.pow(550.0 / wl_nm, 4)
        xyz = ciexyz.xyz_from_wavelength(wl_nm)
        spectrum_y[i][1] = xyz[1] * rayleigh
    pylab.clf()
    pylab.title('Perceptual Brightness of Rayleigh Scattered Light')
    pylab.xlabel('Wavelength (nm)')
    pylab.ylabel('CIE $Y$ / $\lambda^4$')
    spectrum_subplot(spectrum_y)
    tighten_x_axis(spectrum_y[:, 0])
    # done
    filename = 'Visual_scattering'
    print('Saving plot %s' % str(filename))
    pylab.savefig(filename)
Ejemplo n.º 21
0
def visible_spectrum_plot():
    '''Plot the visible spectrum, as a plot vs wavelength.'''
    spectrum = ciexyz.empty_spectrum()
    (num_wl, num_cols) = spectrum.shape
    # get rgb colors for each wavelength
    rgb_colors = numpy.empty((num_wl, 3))
    for i in xrange(0, num_wl):
        xyz = ciexyz.xyz_from_wavelength(spectrum[i][0])
        rgb = colormodels.rgb_from_xyz(xyz)
        rgb_colors[i] = rgb
    # scale to make brightest rgb value = 1.0
    rgb_max = numpy.max(rgb_colors)
    scaling = 1.0 / rgb_max
    rgb_colors *= scaling
    # plot colors and rgb values vs wavelength
    color_vs_param_plot(spectrum[:, 0],
                        rgb_colors,
                        'The Visible Spectrum',
                        'VisibleSpectrum',
                        tight=True,
                        xlabel=r'Wavelength (nm)',
                        ylabel=r'RGB Color')
Ejemplo n.º 22
0
def visible_spectrum_plot ():
    '''Plot the visible spectrum, as a plot vs wavelength.'''
    spectrum = ciexyz.empty_spectrum()
    (num_wl, num_cols) = spectrum.shape
    # get rgb colors for each wavelength
    rgb_colors = numpy.empty ((num_wl, 3))
    for i in xrange (0, num_wl):
        xyz = ciexyz.xyz_from_wavelength (spectrum [i][0])
        rgb = colormodels.rgb_from_xyz (xyz)
        rgb_colors [i] = rgb
    # scale to make brightest rgb value = 1.0
    rgb_max = numpy.max (rgb_colors)
    scaling = 1.0 / rgb_max
    rgb_colors *= scaling        
    # plot colors and rgb values vs wavelength
    color_vs_param_plot (
        spectrum [:,0],
        rgb_colors,
        'The Visible Spectrum',
        'VisibleSpectrum',
        tight = True,
        xlabel = r'Wavelength (nm)',
        ylabel = r'RGB Color')
Ejemplo n.º 23
0
def visible_spectrum_table (filename='visible_spectrum.html'):
    '''Write an HTML table with the visible spectrum colors.'''
    spectrum = ciexyz.empty_spectrum()
    (num_wl, num_cols) = spectrum.shape
    # get rgb colors for each wavelength
    rgb_colors_1 = numpy.empty ((num_wl, 3))
    rgb_colors_2 = numpy.empty ((num_wl, 3))
    for i in range (0, num_wl):
        xyz = ciexyz.xyz_from_wavelength (spectrum [i][0])
        rgb_1 = colormodels.rgb_from_xyz (xyz)
        rgb_2 = colormodels.brightest_rgb_from_xyz (xyz)
        rgb_colors_1 [i] = rgb_1
        rgb_colors_2 [i] = rgb_2
    # scale 1 to make brightest rgb value = 1.0
    rgb_max = numpy.max (rgb_colors_1)
    scaling = 1.0 / rgb_max
    rgb_colors_1 *= scaling
    # write HTML file

    def write_link (f, url, text):
        '''Write an html link.'''
        link = '<a href="%s">%s</a><br/>\n' % (url, text)
        f.write (link)

    f = open (filename, 'w')
    # html headers
    f.write ('<html>\n')
    f.write ('<head>\n')
    f.write ('<title>Colors of Pure Spectral Lines</title>\n')
    f.write ('</head>\n')
    f.write ('<body>\n')
    f.write ('<p><h1>Colors of Pure Spectral Lines</h1></p>\n')
    f.write ('<p>%s</p>\n' % 'White added to undisplayable pure colors to fit into rgb space.')
    f.write ('<hr/>\n')
    # table header
    f.write ('<table border cellpadding="5">\n')
    f.write ('<tr>\n')
    f.write ('<th>Wavelength</th>\n')
    f.write ('<th>R</th>\n')
    f.write ('<th>G</th>\n')
    f.write ('<th>B</th>\n')
    f.write ('<th>Hex Code</th>\n')
    f.write ('<th width=200>Full Brightness</th>\n')
    f.write ('<th width=200>Perceptual Brightness</th>\n')
    f.write ('</tr>\n')
    # each row

    for i in range (0, num_wl):
        irgb_1 = colormodels.irgb_from_rgb (rgb_colors_1 [i])
        irgb_2 = colormodels.irgb_from_rgb (rgb_colors_2 [i])
        red   = irgb_2 [0]
        green = irgb_2 [1]
        blue  = irgb_2 [2]
        hexstr_1 = colormodels.irgb_string_from_irgb (irgb_1)
        hexstr_2 = colormodels.irgb_string_from_irgb (irgb_2)

        iwl = spectrum [i][0]
        code = '%.1f nm' % iwl

        f.write ('<tr>\n')
        f.write ('<td>%s</td>\n' % (code))
        f.write ('<td>%d</td>\n' % (red))
        f.write ('<td>%d</td>\n' % (green))
        f.write ('<td>%d</td>\n' % (blue))
        f.write ('<td>%s</td>\n' % (hexstr_2))
        swatch = "&nbsp;"
        f.write ('<td bgcolor="%s">%s</td>\n' % (hexstr_2, swatch))
        f.write ('<td bgcolor="%s">%s</td>\n' % (hexstr_1, swatch))
        f.write ('</tr>\n')

    f.write ('</table>\n')
    # references
    f.write ('<hr/>\n')
    f.write ('<p>References</p>\n')
    # one source for data
    write_link (f, 'http://goffgrafix.com/pantone-rgb-100.php', 'Goffgrafix.com')
    # another source with basically the same data
    write_link (f, 'http://www.sandaleo.com/pantone.asp', 'Sandaleo.com')
    # one with more colors including metallic (also some errors), not quite consistent with the first two
    write_link (f, 'http://www.loral.org/Z/Colors/100.html',
        'Loral.org - Conversions based on CorelDRAW v12 Pantone Solid Coated or Pastel Coated tables and sRGB color space.')
    # some colors for various sports teams
    write_link (f, 'http://www.pennjersey.info/forums/questions-answers/7895-pantone-colors-colleges-university-mlb-nfl-teams.html',
        'Pantone colors for some sports teams.')
    # some colors for various national flags
    write_link (f, 'http://desktoppub.about.com/od/colorpalettes/l/aa_flagcolors.htm', 'What color is your flag? Pantone colors for some flags.')
    write_link (f, 'http://desktoppub.about.com/library/weekly/blcpflagsrwb.htm', 'Red, White, &amp Blue - Pantone colors for some flags.')
    write_link (f, 'http://desktoppub.about.com/library/weekly/blcpflagsyellow.htm', 'Yellow or Gold - Pantone colors for some flags.')
    write_link (f, 'http://desktoppub.about.com/library/weekly/blcpflagsgreen.htm', 'Green - Pantone colors for some flags.')
    write_link (f, 'http://desktoppub.about.com/library/weekly/blcpatrioticswatches.htm', 'Color swatches - Pantone colors for some flags.')
    # official Pantone webpages
    write_link (f, 'http://pantone.com/pages/pantone/Pantone.aspx?pg=19970&ca=25', 'An official PANTONE page')
    write_link (f, 'http://pantone.com/pages/products/product.aspx?ca=1&pid=293&', 'Another official PANTONE page')
    # html ending
    f.write ('</body>\n')
    f.write ('</html>\n')
    f.close()
Ejemplo n.º 24
0
def visible_spectrum_table(filename='visible_spectrum.html'):
    '''Write an HTML table with the visible spectrum colors.'''
    spectrum = ciexyz.empty_spectrum()
    (num_wl, num_cols) = spectrum.shape
    # get rgb colors for each wavelength
    rgb_colors_1 = numpy.empty((num_wl, 3))
    rgb_colors_2 = numpy.empty((num_wl, 3))
    for i in range(0, num_wl):
        xyz = ciexyz.xyz_from_wavelength(spectrum[i][0])
        rgb_1 = colormodels.rgb_from_xyz(xyz)
        rgb_2 = colormodels.brightest_rgb_from_xyz(xyz)
        rgb_colors_1[i] = rgb_1
        rgb_colors_2[i] = rgb_2
    # scale 1 to make brightest rgb value = 1.0
    rgb_max = numpy.max(rgb_colors_1)
    scaling = 1.0 / rgb_max
    rgb_colors_1 *= scaling

    # write HTML file

    def write_link(f, url, text):
        '''Write an html link.'''
        link = '<a href="%s">%s</a><br/>\n' % (url, text)
        f.write(link)

    f = open(filename, 'w')
    # html headers
    f.write('<html>\n')
    f.write('<head>\n')
    f.write('<title>Colors of Pure Spectral Lines</title>\n')
    f.write('</head>\n')
    f.write('<body>\n')
    f.write('<p><h1>Colors of Pure Spectral Lines</h1></p>\n')
    f.write('<p>%s</p>\n' %
            'White added to undisplayable pure colors to fit into rgb space.')
    f.write('<hr/>\n')
    # table header
    f.write('<table border cellpadding="5">\n')
    f.write('<tr>\n')
    f.write('<th>Wavelength</th>\n')
    f.write('<th>R</th>\n')
    f.write('<th>G</th>\n')
    f.write('<th>B</th>\n')
    f.write('<th>Hex Code</th>\n')
    f.write('<th width=200>Full Brightness</th>\n')
    f.write('<th width=200>Perceptual Brightness</th>\n')
    f.write('</tr>\n')
    # each row

    for i in range(0, num_wl):
        irgb_1 = colormodels.irgb_from_rgb(rgb_colors_1[i])
        irgb_2 = colormodels.irgb_from_rgb(rgb_colors_2[i])
        red = irgb_2[0]
        green = irgb_2[1]
        blue = irgb_2[2]
        hexstr_1 = colormodels.irgb_string_from_irgb(irgb_1)
        hexstr_2 = colormodels.irgb_string_from_irgb(irgb_2)

        iwl = spectrum[i][0]
        code = '%.1f nm' % iwl

        f.write('<tr>\n')
        f.write('<td>%s</td>\n' % (code))
        f.write('<td>%d</td>\n' % (red))
        f.write('<td>%d</td>\n' % (green))
        f.write('<td>%d</td>\n' % (blue))
        f.write('<td>%s</td>\n' % (hexstr_2))
        swatch = "&nbsp;"
        f.write('<td bgcolor="%s">%s</td>\n' % (hexstr_2, swatch))
        f.write('<td bgcolor="%s">%s</td>\n' % (hexstr_1, swatch))
        f.write('</tr>\n')

    f.write('</table>\n')
    # references
    f.write('<hr/>\n')
    f.write('<p>References</p>\n')
    # one source for data
    write_link(f, 'http://goffgrafix.com/pantone-rgb-100.php',
               'Goffgrafix.com')
    # another source with basically the same data
    write_link(f, 'http://www.sandaleo.com/pantone.asp', 'Sandaleo.com')
    # one with more colors including metallic (also some errors), not quite consistent with the first two
    write_link(
        f, 'http://www.loral.org/Z/Colors/100.html',
        'Loral.org - Conversions based on CorelDRAW v12 Pantone Solid Coated or Pastel Coated tables and sRGB color space.'
    )
    # some colors for various sports teams
    write_link(
        f,
        'http://www.pennjersey.info/forums/questions-answers/7895-pantone-colors-colleges-university-mlb-nfl-teams.html',
        'Pantone colors for some sports teams.')
    # some colors for various national flags
    write_link(
        f, 'http://desktoppub.about.com/od/colorpalettes/l/aa_flagcolors.htm',
        'What color is your flag? Pantone colors for some flags.')
    write_link(f,
               'http://desktoppub.about.com/library/weekly/blcpflagsrwb.htm',
               'Red, White, &amp Blue - Pantone colors for some flags.')
    write_link(
        f, 'http://desktoppub.about.com/library/weekly/blcpflagsyellow.htm',
        'Yellow or Gold - Pantone colors for some flags.')
    write_link(
        f, 'http://desktoppub.about.com/library/weekly/blcpflagsgreen.htm',
        'Green - Pantone colors for some flags.')
    write_link(
        f,
        'http://desktoppub.about.com/library/weekly/blcpatrioticswatches.htm',
        'Color swatches - Pantone colors for some flags.')
    # official Pantone webpages
    write_link(f,
               'http://pantone.com/pages/pantone/Pantone.aspx?pg=19970&ca=25',
               'An official PANTONE page')
    write_link(f,
               'http://pantone.com/pages/products/product.aspx?ca=1&pid=293&',
               'Another official PANTONE page')
    # html ending
    f.write('</body>\n')
    f.write('</html>\n')
    f.close()