Patch title: Release 94 bulk changes
Abstract:
File: /pliant/graphic/color/editor.page
Key:
    Removed line
    Added line
module "/pliant/language/compiler.pli"
module "/pliant/graphic/misc/float.pli"
module "/pliant/admin/file.pli"
module "/pliant/protocol/http/uvar.pli"
module "/pliant/language/data/cache.pli"
module "database.pli"
module "spectrum.pli"
module "color.pli"
module "adjust.pli"
module "gradation.pli"
module "ink.pli"
module "gamut.pli"
module "spectro.pli"

module "/pliant/math/curve.pli"
module "/pliant/graphic/image/prototype.pli"
module "/pliant/graphic/image/pixmap.pli"
module "/pliant/graphic/filter/io.pli"
module "/pliant/util/encoding/http.pli"

module "/pliant/protocol/http/style/draw.pli"

requires "color_administrator"

gvar CBool initialized
constant { initialized := false }


method page display_spectrum filter1 filter2 filter3 scale_x scale_y
  arg_rw HtmlPage page ; arg ColorSpectrum32 filter1 filter2 filter3 ; arg Int scale_x scale_y
  var Link:ImagePixmap pixmap :> new ImagePixmap
  pixmap setup (image_prototype 700 100 400 0 300*scale_x+1 100*scale_y+1 color_gamut:"rgb") ""
  for (var Int w) 400 700
    (var ColorSpectrum sp) set_step 10
    for (var Int i) 400 700 step 10
      sp set_measure i 0.1
    sp set_measure w-w%10 0.1+0.9*(1-w%10/10)
    sp set_measure w-w%10+10 0.1+0.9*(w%10/10)
    var ColorRGB888 rgb := cast filter_XYZ:(cast sp ColorSpectrum32) ColorRGB888
    for (var Int iy) 0 100*scale_y
      for (var Int i) 0 scale_x-1
        if (700-w)*scale_x+i<pixmap:size_x
          memory_copy addressof:rgb (pixmap pixel (700-w)*scale_x+i iy) ColorRGB888:size
  for (var Int d) 0 2
    var ColorSpectrum32 filter := shunt d=0 filter1 d=1 filter2 filter3
    if filter<>undefined
      var ColorSpectrum s := cast filter ColorSpectrum
      for (var Int w) 400 700
        var Float z := s w
        if z>=0 and z<=1
          (pixmap pixel (700-w)*scale_x (cast 100*scale_y*(1-z) Int)) map uInt8 d := 255
  var Str f1 := string (cast filter1 ColorSpectrum)
  var Str f2 := string (cast filter2 ColorSpectrum)
  var Str f3 := string (cast filter3 ColorSpectrum)
  draw pixmap position
    f1 parse (var ColorSpectrum s1a)
    f2 parse (var ColorSpectrum s2a)
    f3 parse (var ColorSpectrum s3a)
    display_spectrum (cast s1a ColorSpectrum32) (cast s2a ColorSpectrum32) (cast s3a ColorSpectrum32) 2 5

method page display_spectrum filter1 filter2 filter3
  arg_rw HtmlPage page ; arg ColorSpectrum32 filter1 filter2 filter3
  display_spectrum filter1 filter2 filter3 1 1

if (options option "device") and (options option "channel")
  var Link:ImagePixmap img :> new ImagePixmap
  img setup (image_prototype 0 0 501 501 501 501 color_gamut:"rgb") ""
  var ColorRGB888 black ; black r := 0 ; black g := 0 ; black b := 0
  var ColorRGB888 dark ; dark r := 40h ; dark g := 40h ; dark b := 40h
  var ColorRGB888 middle ; middle r := 80h ; middle g := 80h ; middle b := 80h
  var ColorRGB888 light ; light r := 0C0h ; light g := 0C0h ; light b := 0C0h
  for (var Int i) 0 500
    img fill 0 i 501 addressof:light
  for (var Int i) 0 500 step 5
    for (var Int j) 0 500 step 5
      (img pixel i j) map ColorRGB888 := shunt i%50=0 or j%50=0 black i%25=0 or j%25=0 dark middle
  for (var Int i) 0 2
    for (var Int j) 0 2
      for (var Int k) -2 2
        var Int xx := i*250+k
        var Int yy := j*250
        if xx>=0 and xx<=500 and yy>=0 and yy<=500
          (img pixel xx yy) map ColorRGB888 := black
        var Int xx := i*250
        var Int yy := j*250+k
        if xx>=0 and xx<=500 and yy>=0 and yy<=500
          (img pixel xx yy) map ColorRGB888 := black
  var Data:ColorDevice z_d :> color_database:data:device:(options option "device" Str)
  var Data:ColorChannel z_ch :> z_d:channel:(options option "channel" Str)
  var ColorSpectrum32 z_s0 := z_ch s0
  var ColorSpectrum32 z_s100 := z_ch s100
  if z_s0=undefined and z_s100=undefined
    return
  var Float zero := z_ch:options+" "+z_d:options option "zero" Float 0
  var Str adjust := z_ch:options+" "+z_d:options option "adjust" Str
  var Curve ac := var Curve empty_curve
  for (var Int i) 0 100
    ac through i/100 (dot_unadjust i/100 adjust)
  ac compute both
  var ColorSpectrum32 zz := cast zero ColorSpectrum32
  var Curve curve1 := var Curve empty_curve
  var Curve curve2 := var Curve empty_curve
  var Curve curve3 := var Curve empty_curve
  var Float range_x := 1
  var Float range_y := 1
  each sample z_ch:sample filter (keyof:sample parse (var Int i)) sort (right keyof:sample 9 " ")
    keyof:sample parse (var Float x)
    var Float y := ink_density color_spectrum32:sample-zz z_s0-zz z_s100-zz
    curve1 through x y
    curve1 through x (ac x y 1e-6)
    var Float y := ink_surface color_spectrum32:sample-zz z_s0-zz z_s100-zz
    curve2 through x y
    curve2 through x (ac x y 1e-6)
    var Float y := ink_thickness color_spectrum32:sample-zz z_s0-zz z_s100-zz
    curve3 through x y
    curve3 through x (ac x y 1e-6)
    range_x := max range_x x
    range_y := max range_y y
  curve1 compute y_from_x
  curve2 compute y_from_x
  curve3 compute y_from_x
  if curve3=success
    var ColorRGB888 blue ; blue r := 0 ; blue g := 0 ; blue b := 255
    for (var Int i) 0 500
      var Float y := (curve3 y i/500*range_x 1e-6)/range_y
      if y=defined
        var Int j := cast y*500 Int
        if j>=0 and j<=500
          (img pixel i 500-j) map ColorRGB888 := blue
  if curve2=success
    var ColorRGB888 green ; green r := 0 ; green g := 255 ; green b := 0
    for (var Int i) 0 500
      var Float y := (curve2 y i/500*range_x 1e-6)/range_y
      if y=defined
        var Int j := cast y*500 Int
        if j>=0 and j<=500
          (img pixel i 500-j) map ColorRGB888 := green
  if curve1=success
    var ColorRGB888 red ; red r := 255 ; red g := 0 ; red b := 0
    for (var Int i) 0 500
      var Float y := (curve1 y i/500*range_x 1e-6)/range_y
      if y=defined
        var Int j := cast y*500 Int
        if j>=0 and j<=500
          (img pixel i 500-j) map ColorRGB888 := red
  reset_http_answer
  http_request send_header "mime [dq]image/png[dq]"
  img save http_request:answer_stream "filter [dq].png[dq]"
  http_request send_footer
  return
  
title "Color database editor"

para
  [Please notice that in Pliant terminology, a 'color gamut', a 'color device' and a 'color profile' are basically all the same thing.]

page button "load new parameters"
  file_tree_delete "data:/pliant/graphic/cache/"
  cache_shrink 0 cache_class_costy
  reload_page

uvar Str src_gamut_name densities dest_gamut_name

para
  page note "sample color conversion tool"
    title "Sample color conversion"
    input "Source gamut: " src_gamut_name length 80
    input "Source densities (in %): " densities length 40
    input "Destination gamut: " dest_gamut_name length 80
    button "Compute"
      reload_page
    para
      var Link:ColorGamut src_gamut :> color_gamut src_gamut_name
      var Link:ColorGamut dest_gamut :> color_gamut dest_gamut_name
      if src_gamut=success and dest_gamut=success
        var ColorBuffer pixel
        var Str all := densities ; var Int i := 0
        while i<gamut_maximum_dimension and i<src_gamut:dimension and (all parse (var Float d) any:(var Str remain))
          pixel:bytes i := cast d/100*255 Int
          all := remain ; i += 1
        var ColorXYZ pixel_color := src_gamut simulate addressof:pixel
        var ColorXYZ pixel_color2 := filter_XYZ (src_gamut simulate2 addressof:pixel)
        var ColorSpectrum32 pixel_spectrum := src_gamut simulate2 addressof:pixel
        var ColorXYZ pixel_color2 := shunt pixel_spectrum=defined filter_XYZ:pixel_spectrum pixel_color
        dest_gamut formulate pixel_color addressof:(var ColorBuffer result)
        var ColorXYZ result_color := dest_gamut simulate addressof:result
        var ColorXYZ result_color2 := filter_XYZ (dest_gamut simulate2 addressof:result)
        var ColorSpectrum32 result_spectrum := dest_gamut simulate2 addressof:result
        var ColorXYZ result_color2 := shunt result_spectrum=defined filter_XYZ:result_spectrum result_color
        table columns 4 border 0
          cell
            table columns 2
            table columns 3
              cell header [Ink]
              cell header [Encoded[lf]density]
              cell header
                font color (color hsl 0 0 50)
                  [Thickness]
              src_gamut decode addressof:pixel (var (Array Float32 gamut_maximum_dimension) l)
              for (var Int i) 0 src_gamut:dimension-1
                cell
                  text (src_gamut query "component_name "+string:i)
                cell
                  text (string pixel:bytes:i/255*100 "fixed 1")+" %"
                cell
                  font color (color hsl 0 0 50)
                    text (string l:i*100 "fixed 1")+" %"
          cell
            void
          cell
            void
          cell
            table columns 2
            table columns 3
              cell header [Ink]
              cell header [Encoded[lf]density]
              cell header
                font color (color hsl 0 0 50)
                  [Thickness]
              dest_gamut decode addressof:result (var (Array Float32 gamut_maximum_dimension) l)
              for (var Int i) 0 dest_gamut:dimension-1
                cell
                  text (dest_gamut query "component_name "+string:i)
                cell
                  text (string result:bytes:i/255*100 "fixed 1")+" %"
                cell
                  font color (color hsl 0 0 50)
                    text (string l:i*100 "fixed 1")+" %"
          cell
            var ColorXYZn colorn := cast pixel_color ColorXYZn
            text "XYZn "+(string colorn:X "fixed 3")+" "+(string colorn:Y "fixed 3")+" "+(string colorn:Z "fixed 3") ; eol
            var ColorLCh lch := cast pixel_color ColorLCh
            text "LCh "+(string lch:L "fixed 1")+" "+(string lch:C "fixed 1")+" "+(string lch:h "fixed 0")
          cell
            var ColorXYZn colorn := cast pixel_color2 ColorXYZn
            text "XYZn "+(string colorn:X "fixed 3")+" "+(string colorn:Y "fixed 3")+" "+(string colorn:Z "fixed 3") ; eol
            var ColorLCh lch := cast pixel_color ColorLCh
            text "LCh "+(string lch:L "fixed 1")+" "+(string lch:C "fixed 1")+" "+(string lch:h "fixed 0")
          cell
            var ColorXYZn colorn := cast result_color2 ColorXYZn
            text "XYZn "+(string colorn:X "fixed 3")+" "+(string colorn:Y "fixed 3")+" "+(string colorn:Z "fixed 3") ; eol
            var ColorLCh lch := cast result_color ColorLCh
            text "LCh "+(string lch:L "fixed 1")+" "+(string lch:C "fixed 1")+" "+(string lch:h "fixed 0")
          cell
            var ColorXYZn colorn := cast result_color ColorXYZn
            text "XYZn "+(string colorn:X "fixed 3")+" "+(string colorn:Y "fixed 3")+" "+(string colorn:Z "fixed 3") ; eol
            var ColorLCh lch := cast result_color ColorLCh
            text "LCh "+(string lch:L "fixed 1")+" "+(string lch:C "fixed 1")+" "+(string lch:h "fixed 0")
          cell color (cast pixel_color ColorRGB888)
            fixed [ ]
          cell color (cast pixel_color2 ColorRGB888)
            fixed [ ]
          cell color (cast result_color2 ColorRGB888)
            fixed [ ]
          cell color (cast result_color ColorRGB888)
            fixed [ ]
    para
      display_spectrum (src_gamut simulate2 addressof:pixel) (dest_gamut simulate2 addressof:result) (var ColorSpectrum32 no_spectrum)
    para
      text "CMC("+string:cmc_distance_l_parameter+","+string:cmc_distance_c_parameter+") distance is " ; bold text:(string (cmc_distance (cast pixel_color ColorXYZ) (cast result_color ColorXYZ)) "fixed 1") ; eol
  eol
  page note "compute CMC distance"
  page note "compute LCh CMC distance"
    title "CMC distance"
    input "Reference LCh: " (var Str color1) length 20
    input "Effective LCh: " (var Str color2) length 20
    page button "Compute CMC distance"
      if (color1 parse (var Float l1) (var Float c1) (var Float h1))
        if (color2 parse (var Float l2) (var Float c2) (var Float h2))
          var ColorLCh lch1 ; lch1 L := l1 ; lch1 C := c1 ; lch1 h := h1
          var ColorLCh lch2 ; lch2 L := l2 ; lch2 C := c2 ; lch2 h := h2
          text "Reference LCh: "+(string l1 "fixed 1")+" "+(string c1 "fixed 1")+" "+(string h1 "fixed 0") ; eol
          text "Effective LCh: "+(string l2 "fixed 1")+" "+(string c2 "fixed 1")+" "+(string h2 "fixed 0") ; eol
          text "CMC distance is "+(string (cmc_distance (cast lch1 ColorLab) (cast lch2 ColorLab)) "fixed 1") ; eol
          table columns 2
            cell
              text "Reference LCh: "+(string l1 "fixed 1")+" "+(string c1 "fixed 1")+" "+(string h1 "fixed 0") ; eol
            cell color (cast (cast lch1 ColorXYZ) ColorRGB888)
              fixed [   ]
            cell
              text "Effective LCh: "+(string l2 "fixed 1")+" "+(string c2 "fixed 1")+" "+(string h2 "fixed 0") ; eol
            cell color (cast (cast lch2 ColorXYZ) ColorRGB888)
              fixed [   ]
            cell
              text "CMC distance is "+(string (cmc_distance (cast lch1 ColorLab) (cast lch2 ColorLab)) "fixed 1") ; eol
            cell
              void
  eol
  page note "compute spectrum CMC distance"
    title "CMC distance"
    input "Reference white: " (var Str white1) length 80
    input "Reference spectrum: " (var Str spectrum1) length 80
    input "Effective white: " (var Str white2) length 80
    input "Effective spectrum: " (var Str spectrum2) length 80
    page button "Compute CMC distance"
      if (white1 parse any ":" (var ColorSpectrum w1)) or (white1 parse (var ColorSpectrum w1))
        if (spectrum1 parse any ":" (var ColorSpectrum s1)) or (spectrum1 parse (var ColorSpectrum s1))
          if (white2 parse any ":" (var ColorSpectrum w2)) or (white2 parse (var ColorSpectrum w2))
            if (spectrum2 parse any ":" (var ColorSpectrum s2)) or (spectrum2 parse (var ColorSpectrum s2))
              var ColorLCh lch1 := cast (filter_XYZ s1/w1) ColorLCh
              var ColorLCh lch2 := cast (filter_XYZ s2/w2) ColorLCh
              table columns 2
                cell
                  text "Reference LCh: "+(string lch1:L "fixed 1")+" "+(string lch1:C "fixed 1")+" "+(string lch1:h "fixed 0") ; eol
                cell color (cast (cast lch1 ColorXYZ) ColorRGB888)
                  fixed [   ]
                cell
                  text "Effective LCh: "+(string lch2:L "fixed 1")+" "+(string lch2:C "fixed 1")+" "+(string lch2:h "fixed 0") ; eol
                cell color (cast (cast lch2 ColorXYZ) ColorRGB888)
                  fixed [   ]
                cell
                  text "CMC distance is "+(string (cmc_distance (cast lch1 ColorLab) (cast lch2 ColorLab)) "fixed 1") ; eol
                cell
                  void

table columns 3
  cell header [Device]
  cell void
  cell header [Description]
  each d color_database:data:device
    cell
      text keyof:d
    cell
      text d:label
    cell
      page button "edit"
        title "Color device '"+keyof:d+"'"
        page note "printer settings used to build this profile"
          title "Printer settings for '"+keyof:d+"' color profile"
          var Data:ColorPrinter p :> d printer
          table columns 3 border 0
            cell [Driver:]
            cell
              input "" p:driver length 10
            cell
              [The filter is the Pliant driver.] ; eol
              [Most common filter are] ; fixed [ escp2 ] ; [for Epson stylus line,]
              fixed [ pcl ] ; [for HP Designjet (does not work on HP Desktop inkjet printers), ]
              [and ] ; fixed [ gimprint ] ; [if the printer will be driven using Gimp-print free software.]
            cell [Model:]
            cell
              input "" p:model length 20
            cell
              [Must be one of the models the driver is awared of.]
            cell [Extra options:]
            cell
              input "" p:options length 40
            cell
              [As an example, the] ; fixed [ escp2 ] ; [driver recognizes] ; fixed [ unidirectional ] ; [option.]
            cell [Paper name:]
            cell
              input "" p:paper length 40 noeol
            cell
              [This is informative only.]
            cell [Paper size:]
            cell
              input "" p:size_x length 4 noeol
              input " x " p:size_y length 4 noeol
              [ mm]
            cell
              void
            cell [Margins:]
            cell
              input "L" p:margin_left length 3 noeol
              input "T" p:margin_top length 3 noeol
              input "R" p:margin_right length 3 noeol
              input "B" p:margin_bottom length 3 noeol
              [ mm]
            cell
              void
            cell [R鳯lution:]
            cell
              input "" p:resolution_x length 4 noeol
              input " x " p:resolution_y length 4 noeol
              [ dpi]
            cell
              void
            cell [Antialiasing:]
            cell
              input "" p:antialiasing_x length 1 noeol
              input " x " p:antialiasing_y length 1
            cell
              [Use no antialiasing if your computer is slow, 2 if your computer is faster than the printer.] 
            cell [Sharpening:]
            cell
              input "" p:sharpening length 5
            cell
              [Leave it blank unless you want to experiment.]
            cell [Maximum density:]
            cell
              input "" p:limit length 5
            cell
              [Leave it blank unless you know what you do: this is not the right way to correct a poor calibration.]
            cell [Middle adjustment:]
            cell
              input "" p:middle length 5
            cell
              [Leave it blank unless you know what you do: this is not the right way to correct a poor calibration.]
            cell [Gamut:]
            cell
              input "" p:gamut length 40
            cell
              void
            cell [Calibration steps:]
            cell
              input "" p:grid_steps length 2
            cell
              [How many steps do we compute on the calibration grid in each dimension. ]
              [33 is perfect but will require several hours of calibration on a fast computer, 17 is high quality, and 9 is correct.]
          button "Update"
            goto_backward
        table columns 2 border 0
          cell [Label:]
          cell
            input "" d:label length 60
          cell [Description:]
          cell
            text_input "" d:comment columns 60 rows 10
          cell [Gamut extra options:]
          cell
            input "" d:options length 60 noeol
            button "Update"
              cache_shrink 0 cache_class_costy
              goto_backward
            link "what do these options mean" "/pliant/graphic/color/adjust"
          
        table columns 5
          cell header [Ink]
          cell header [Sample]
          cell header [Opacity]
          cell void
          cell header [Options]
          each ch d:channel
            cell
              text keyof:ch
            var ColorSpectrum32 a_s0 := ch s0
            var ColorSpectrum32 a_s100 := ch s100
            if a_s0=defined and a_s100=defined
              cell color (cast (filter_XYZ a_s100/a_s0) ColorRGB888)
                fixed [ ]
            else
              cell void
            cell
              if (ch:options option "opacity" Float)=defined
                text string:(ch:options option "opacity" Float)
            cell
              page button "edit"
                title "Ink '"+keyof:ch+"' for device '"+keyof:d+"'"
                var ColorSpectrum32 s0 := ch s0
                var ColorSpectrum32 s100 := ch s100
                var Float zero := ch:options+" "+d:options option "zero" Float 0
                var ColorSpectrum32 z := cast zero ColorSpectrum32
                var Float deaden := ch:options+" "+d:options option "deaden" Float 0
                var CBool composed := (keyof:ch search "+" -1)<>(-1)
                var Int maxi := shunt (exists ch:sample:"255") 255 100
                var Float display := ch:options option "density_exposure_display" Float 0
                if s0=defined and s100=defined
                  check ColorSpectrum32:size=31*Float32:size
                  table columns 4 border 0
                    cell
                      var Float mi := 1
                      var Float ma := 0
                      for (var Int w) 0 30
                        mi := min mi (addressof:s100 map Float32 w)
                        ma := max ma (addressof:s100 map Float32 w)
                      text "Absolute reflexion range: "
                      fixed
                        text (string (cast mi*1000 Int)/1000)+" "+(string (cast ma*1000 Int)/1000)
                      eol
                      var Float mi := 1
                      var Float ma := 0
                      for (var Int w) 0 30
                        mi := min mi (addressof:s100 map Float32 w)/(addressof:s0 map Float32 w)
                        ma := max ma (addressof:s100 map Float32 w)/(addressof:s0 map Float32 w)
                      text "Relative reflexion range: "
                      fixed
                        text (string (cast mi*1000 Int)/1000)+" "+(string (cast ma*1000 Int)/1000)
                      eol
                      var ColorXYZ xyz := filter_XYZ s100/s0
                      text "XYZ: "
                      fixed
                        text (string xyz:X "fixed 3")+" "+(string xyz:Y "fixed 3")+" "+(string xyz:Z "fixed 3")
                      eol
                      var ColorYxy yxy := cast xyz ColorYxy
                      text "Yxy: "
                      fixed
                        text (string yxy:Y "fixed 3")+" "+(string yxy:x "fixed 3")+" "+(string yxy:y "fixed 3")
                      eol
                      var ColorLab lab := cast xyz ColorLab
                      text "L*a*b*: "
                      fixed
                        text (string lab:L "fixed 1")+" "+(string lab:a "fixed 1")+" "+(string lab:b "fixed 1")
                      eol
                      text "Zero: "+(string zero "fixed 3")
                      eol
                      text "Deaden: "+(string deaden "fixed 3")
                    var ColorXYZ paper := filter_XYZ s0
                    cell
                      [Paper:] ; eol
                      var ColorLCh lch := cast paper ColorLCh
                      [L*C*h] ; small [ ab] ; eol
                      fixed
                        text (string lch:L "fixed 1") ; fixed [ ] ; text (string lch:C "fixed 1") ; fixed [ ] ; text (string lch:h "fixed 0") ; eol
                      [Sample and spectrum ->]
                    cell
                      var ColorRGB888 rgb := cast paper ColorRGB888
                      image "sample/r"+string:(cast rgb:r Int)+"g"+string:(cast rgb:g Int)+"b"+string:(cast rgb:b Int)
                    cell
                      display_spectrum s0 (var ColorSpectrum32 no_spectrum) (cast no_spectrum ColorSpectrum32)
                input "Options: " ch:options length 60 noeol
                var Float display := ch:options option "density_exposure_display" Float 0
                page button "Update"
                  cache_shrink 0 cache_class_costy
                  goto_backward
                table columns (shunt composed 9 7)
                  cell header [Color]
                  cell header
                    [Linear[lf]Thickness[lf]Surface]
                  cell header [Density]
                  cell header [Opacity]
                  cell header [Sample]
                  cell header
                    [L*C*h] ; small [ ab]
                  if composed
                    cell header [computation[lf]color]
                    cell header [computation[lf]sample]
                  cell header
                    [Spectrum] ; eol
                    small [red is measured, green is computed]
                  each sample ch:sample sort (right keyof:sample 3 " ")
                    cell
                      text keyof:sample
                    cell
                      if s0=defined
                        var ColorXYZ wished := filter_XYZ (color_spectrum32:sample-z)/(s0-z)
                      if s0=defined and s100=defined
                        var Float density := ink_linear color_spectrum32:sample-z s0-z s100-z
                        text (string density*100 "fixed 1")+"%"
                        var ColorXYZ got := filter_XYZ (ink_linear_simulation density s0-z s100-z)/(s0-z)
                        var Float err := lab_distance wished got
                        fixed [ ] ; small { html "&Delta;E " ; text (string err "fixed 1") } 
                        var Float err := cmc_distance wished got
                        fixed [ ] ; small (text "CMC "+(string err "fixed 1"))
                        eol
                        var Float density := ink_thickness color_spectrum32:sample-z s0-z s100-z
                        text (string density*100 "fixed 1")+"%"
                        var ColorXYZ got := filter_XYZ (ink_thickness_simulation density s0-z s100-z)/(s0-z)
                        var Float err := lab_distance wished got
                        fixed [ ] ; small { html "&Delta;E " ; text (string err "fixed 1") } 
                        var Float err := cmc_distance wished got
                        fixed [ ] ; small (text "CMC "+(string err "fixed 1"))
                        eol
                        var Float density := ink_surface color_spectrum32:sample-z s0-z s100-z
                        text (string (cast density*1000 Int)/10)+"%"
                        var ColorXYZ got := filter_XYZ (ink_surface_simulation density s0-z s100-z)/(s0-z)
                        var Float err := lab_distance wished got
                        fixed [ ] ; small { html "&Delta;E " ; text (string err "fixed 1") } 
                        var Float err := cmc_distance wished got
                        fixed [ ] ; small (text "CMC "+(string err "fixed 1"))
                    cell
                      if s0=defined and s100=defined
                        var Float density := ink_density color_spectrum32:sample-z s0-z s100-z
                        bold (text (string (exposure density display)*100 "fixed 1")+"%")
                        if false
                          eol
                          var Float density0 := ink_density color_spectrum32:sample-z s0-z s100-z (the_function ink_density_simulation Float ColorSpectrum32 ColorSpectrum32 -> ColorSpectrum32) 0 1 (var Float err)
                          small (text (string (exposure density0 display)*100 "fixed 1")+"%")
                          eol
                          var Float density2 := ink_density color_spectrum32:sample-z s0-z s100-z (the_function ink_density_simulation Float ColorSpectrum32 ColorSpectrum32 -> ColorSpectrum32) 2 1 (var Float err)
                          small (text (string (exposure density2 display)*100 "fixed 1")+"%")
                    cell
                      text string:(sample option "opacity" Float)
                    cell
                      if s0=defined
                        var ColorRGB888 rgb := cast (filter_XYZ (color_spectrum32:sample-z)/(s0-z)) ColorRGB888
                        image "sample/r"+string:(cast rgb:r Int)+"g"+string:(cast rgb:g Int)+"b"+string:(cast rgb:b Int)
                    cell
                      if s0=defined
                        var ColorLCh lch := cast wished ColorLCh
                        text (string lch:L "fixed 1") ; fixed [ ] ; text (string lch:C "fixed 1") ; fixed [ ] ; text (string lch:h "fixed 0")
                    if composed
                      var ColorSpectrum32 s1 := var ColorSpectrum32 undefined_spectrum
                      var Link:ColorGamut g :> color_gamut keyof:d+":"+keyof:ch ""
                      if g=success and (keyof:sample parse (var Int level))
                        var ColorBuffer pixel1
                        for (var Int i) 0 gamut_maximum_dimension-1
                          pixel1:bytes i := level*255\maxi
                        s1 := g simulate2 addressof:pixel1
                      cell
                        var ColorXYZ wished1 := filter_XYZ s1
                        var ColorLCh lch1 := cast wished1 ColorLCh
                        text (string lch1:L "fixed 1") ; fixed [ ] ; text (string lch1:C "fixed 1") ; fixed [ ] ; text (string lch1:h "fixed 0")
                      cell
                        if s1=defined
                          var ColorRGB888 rgb := cast filter_XYZ:s1 ColorRGB888
                          image "sample/r"+string:(cast rgb:r Int)+"g"+string:(cast rgb:g Int)+"b"+string:(cast rgb:b Int)
                      cell
                        if s0=defined and s1=defined
                          display_spectrum (color_spectrum32:sample-z)/(s0-z) s1-z (var ColorSpectrum32 no_spectrum) 
                    else
                      cell
                        if s0=defined
                          display_spectrum (color_spectrum32:sample-z)/(s0-z) (var ColorSpectrum32 no_spectrum) (var ColorSpectrum32 no_spectrum)
                input "Color level: " (var Str l) noeol
                page button "Measure" noeol
                  var Str s
                  if (l parse any:(var Str l1) "=" any:(var Str l2) "/" any:(var Str l3) "/" any:(var Str l4))
                    l := l1
                    s := color_database:data:device:l2:channel:l3:sample:l4
                  else
                    if not initialized
                      console "initializing spectrocolorimeter interface" eol
                      spectro_init
                      initialized := true
                    s := string spectro_spectrum
                  ch:sample create l
                  ch:sample l := s
                  reload_page
                button "Delete" noeol
                  ch:sample delete l
                  reload_page
                para
                  input "Options: " ch:options length 60 noeol
                  page button "Update" noeol
                    cache_shrink 0 cache_class_costy
                    goto_backward
                  page button "Redraw" noeol
                    cache_shrink 0 cache_class_costy
                    reload_page
                if s0=defined and s100=defined
                  para
                    image "editor.html?"+(http_encode "device "+(string keyof:d)+" channel "+(string keyof:ch))
                    eol ; small [red is density, green is surface,  blue is thickness.]
            cell
              text ch:options
        input "Channel ID: " (var Str cid) noeol
        button "Create new ink" noeol
          d:channel create cid
          reload_page
        button "Delete the ink"
          d:channel delete cid
          reload_page
        table columns 4
          cell header [Color]
          cell header [... is an alias of]
          cell header [Sample]
          cell header [Opacity]
          each a d:alias
            cell
              text keyof:a
            cell
              input "" a
            var Data:ColorChannel ch :> d:channel a
            var ColorSpectrum32 a_s0 := ch s0
            var ColorSpectrum32 a_s100 := ch s100
            if a_s0=defined and a_s100=defined
              cell color (cast (filter_XYZ a_s100/a_s0) ColorRGB888)
                fixed [ ]
            else
              cell void
            cell
              if (ch:options option "opacity" Float)=defined
                text string:(ch:options option "opacity" Float)
        input "Alias ID: " (var Str aid) noeol
        button "Create new alias" noeol
          d:alias create aid
          reload_page
        button "Delete the alias"
          d:alias delete aid
          reload_page
        table columns 2
          cell header [Grid]
          cell header [Steps]
          each g d:grid
            cell
              text keyof:g
            cell
              input "" g length 2
        input "Grid: " (var Str gid) length 40 noeol
        button "Create new grid" noeol
          d:grid create gid
          d:grid gid := undefined
          reload_page
        button "Delete the grid"
          d:grid delete gid
          reload_page
        [A grid value could be 'process_cyan+process_magenta+process_yellow+process_black' specifying that when converting from a gamut using several of these colors, the conversion will use a multidimension grid instead of per channel conversion.]
     

input "Color device ID: " (var Str did) noeol
button "Create new color device" noeol
  color_database:data:device create did
  reload_page
button "Delete the color device"
  color_database:data:device delete did
  reload_page