Patch title: Release 96 bulk changes
Abstract:
File: /pliant/graphic/color/gamut.pli
Key:
    Removed line
    Added line
   
abstract
  ['ColorGamut' data type is defining how a pixel is encoded


type ColorGridConversion
  inherit CachePrototype
  field Array:Float32 mapping
  field Int dim
  field Int steps
  field Int done
  field Int computed
  field Str key
abstract
  ['ColorGamut' data type is defining how a pixel is encoded


type ColorGridConversion
  inherit CachePrototype
  field Array:Float32 mapping
  field Int dim
  field Int steps
  field Int done
  field Int computed
  field Str key
  field CBool inheritate
  field Link:Function convert_function
  field Str convert_name
  field Arrow convert_param




method conv compute src_gamut dest_gamut steps cached
  arg_w ColorGridConversion conv ; oarg ColorGamut src_gamut
function standard_convert_function src_pixel src_gamut dest_pixel dest_gamut param
  arg Address src_pixel ; oarg ColorGamut src_gamut ; arg Address dest_pixel ; oarg ColorGamut dest_gamut ; arg Address param
  var Str options := (dest_gamut query "options") option "convert_adjust" Str
  var ColorXYZ color := src_gamut simulate src_pixel
  color_adjust color options
  dest_gamut formulate color dest_pixel

method conv compute src_gamut dest_gamut steps cached inheritate
  arg_w ColorGridConversion conv ; oarg ColorGamut src_gamut dest_gamut ; arg Int steps ; arg CBool cached inheritate
  var Int dim := src_gamut dimension
  conv dim := dim
  conv steps := steps
  conv:mapping size := steps^dim*dest_gamut:dimension
  for (var Int i) 0 steps^dim-1
    conv:mapping i*dest_gamut:dimension := undefined
  conv done := 0
  conv computed := 0
  if cached
  var Int dim := src_gamut dimension
  conv dim := dim
  conv steps := steps
  conv:mapping size := steps^dim*dest_gamut:dimension
  for (var Int i) 0 steps^dim-1
    conv:mapping i*dest_gamut:dimension := undefined
  conv done := 0
  conv computed := 0
  if cached
    conv key := string_md5_hexa_signature (string src_gamut:
    conv key := string_md5_hexa_signature (string src_gamut:name)+" "+string:(src_gamut query "signature")+" "+(string dest_gamut:name)+" "+string:(dest_gamut query "signature")+" "+string:steps+" "+conv:convert_name+" "+string:grid_conversion_release
    (var Stream s) open "data:/pliant/graphic/cache/"+conv:k
    if s=success
      while s:readline<>""
        void
      s raw_read (addressof conv:mapping:0) conv:mapping:siz
      if s=success
        for (var Int i) 0 steps^dim-1
          if (conv:mapping i*dest_gamut:dimension)=defined
            conv:done += 1
      else
        for (var Int i) 0 steps^dim-1
          conv:mapping i*dest_gamut:dimension := undefined
    (var Stream s) open "data:/pliant/graphic/cache/"+conv:k
    if s=success
      while s:readline<>""
        void
      s raw_read (addressof conv:mapping:0) conv:mapping:siz
      if s=success
        for (var Int i) 0 steps^dim-1
          if (conv:mapping i*dest_gamut:dimension)=defined
            conv:done += 1
      else
        for (var Int i) 0 steps^dim-1
          conv:mapping i*dest_gamut:dimension := undefined
  if inheritate
    check cached
  conv inheritate := inheritate
  if not (exists conv:convert_function)
    conv convert_function :> the_function standard_convert_function Address ColorGamut Address ColorGamut Address


function convert_function_prototype src_pixel src_gamut dest_pixel dest_gamut param fun
  arg Address src_pixel ; oarg ColorGamut src_gamut ; arg Address dest_pixel ; oarg ColorGamut dest_gamut ; arg Address param ; arg Function fun
  indirect

method conv compute_node index src_gamut dest_gamut
  arg_rw ColorGridConversion conv ; arg Int index ; oarg Col
method conv compute_node index src_gamut dest_gamut
  arg_rw ColorGridConversion conv ; arg Int index ; oarg Col
  var Str options := (dest_gamut query "options") option "co
  var Pointer:Float32 p :> conv:mapping index*dest_gamut:dim
  var ColorBuffer src_pixel dest_pixel
  for (var Int d) 0 conv:dim-1
    src_pixel:bytes d := (index\conv:steps^d)%conv:steps*255
  var Pointer:Float32 p :> conv:mapping index*dest_gamut:dim
  var ColorBuffer src_pixel dest_pixel
  for (var Int d) 0 conv:dim-1
    src_pixel:bytes d := (index\conv:steps^d)%conv:steps*255
  var ColorXYZ color := src_gamut simulate addressof:src_pix
  color_adjust color options
  dest_gamut formulate color addressof:dest_pixel
  convert_function_prototype addressof:src_pixel src_gamut addressof:dest_pixel dest_gamut conv:convert_param conv:convert_function
  dest_gamut decode addressof:dest_pixel (var (Array Float32
  for (var Int d) dest_gamut:dimension-1 0 step -1
    addressof:p map Float32 d := components d


method conv compute_node2 index src_gamut dest_gamut
  arg_rw ColorGridConversion conv ; arg Int index ; oarg Col
  dest_gamut decode addressof:dest_pixel (var (Array Float32
  for (var Int d) dest_gamut:dimension-1 0 step -1
    addressof:p map Float32 d := components d


method conv compute_node2 index src_gamut dest_gamut
  arg_rw ColorGridConversion conv ; arg Int index ; oarg Col
  if conv:key<>"" and src_gamut:model=color_gamut_substracti
  if conv:inheritate and src_gamut:model=color_gamut_substractive and dest_gamut:model=color_gamut_substractive
    var Int selected_dim := 0 ; var Int selected_index := 0 
    for (var Int d) 0 conv:dim-1
      var Int i := (index\conv:steps^d)%conv:steps
      if i<>0
        selected_index += i*conv:steps^selected_dim
        selected_inks += "+"+(src_gamut query "component_nam
        selected_dim += 1
    if selected_dim>0 and selected_dim<conv:dim
      var Link:ColorGamut selected_gamut :> color_gamut (src
      if selected_gamut=success
        var Link:ColorGridConversion selected_conv :> color_
        if (selected_conv:mapping selected_index*dest_gamut:
          part compute "recurse compute lazy color conversio
            selected_conv compute_node2 selected_index selec
        for (var Int d) dest_gamut:dimension-1 0 step -1
          conv:mapping index*dest_gamut:dimension+d := selec
        conv done += 1
        return
  part compute "compute lazy color conversion grid node "+(s
    conv compute_node index src_gamut dest_gamut
    conv done += 1
    conv computed += 1
  if conv:key<>""
    if conv:computed%(shunt dest_gamut:name="XYZ" 4096 64)=0
      (var Stream s) open "data:/pliant/graphic/cache/"+conv
      s writeline "Pliant color conversion"
      s writeline "source_gamut "+(string src_gamut:name)
      s writeline "source_options "+string:(src_gamut query 
      s writeline "destination_gamut "+(string dest_gamut:na
      s writeline "destination_options "+string:(dest_gamut 
      s writeline "steps "+(string conv:steps)
      s writeline "release "+string:grid_conversion_release
      s writeline ""
      s raw_write (addressof conv:mapping:0) conv:mapping:si
      s close
      # if not hurry
      #   console "."


function color_grid_conversion src_gamut dest_gamut steps ca
  oarg ColorGamut src_gamut dest_gamut ; arg Int steps ; arg
  var Int dim := src_gamut dimension
  var Int steps1 := shunt steps=defined steps src_gamut:mode
  var Str k := (string src_gamut:name)+" "+string:(src_gamut
  if (cache_open "/pliant/color/conversion/"+k ColorGridConv
    var Int selected_dim := 0 ; var Int selected_index := 0 
    for (var Int d) 0 conv:dim-1
      var Int i := (index\conv:steps^d)%conv:steps
      if i<>0
        selected_index += i*conv:steps^selected_dim
        selected_inks += "+"+(src_gamut query "component_nam
        selected_dim += 1
    if selected_dim>0 and selected_dim<conv:dim
      var Link:ColorGamut selected_gamut :> color_gamut (src
      if selected_gamut=success
        var Link:ColorGridConversion selected_conv :> color_
        if (selected_conv:mapping selected_index*dest_gamut:
          part compute "recurse compute lazy color conversio
            selected_conv compute_node2 selected_index selec
        for (var Int d) dest_gamut:dimension-1 0 step -1
          conv:mapping index*dest_gamut:dimension+d := selec
        conv done += 1
        return
  part compute "compute lazy color conversion grid node "+(s
    conv compute_node index src_gamut dest_gamut
    conv done += 1
    conv computed += 1
  if conv:key<>""
    if conv:computed%(shunt dest_gamut:name="XYZ" 4096 64)=0
      (var Stream s) open "data:/pliant/graphic/cache/"+conv
      s writeline "Pliant color conversion"
      s writeline "source_gamut "+(string src_gamut:name)
      s writeline "source_options "+string:(src_gamut query 
      s writeline "destination_gamut "+(string dest_gamut:na
      s writeline "destination_options "+string:(dest_gamut 
      s writeline "steps "+(string conv:steps)
      s writeline "release "+string:grid_conversion_release
      s writeline ""
      s raw_write (addressof conv:mapping:0) conv:mapping:si
      s close
      # if not hurry
      #   console "."


function color_grid_conversion src_gamut dest_gamut steps ca
  oarg ColorGamut src_gamut dest_gamut ; arg Int steps ; arg
  var Int dim := src_gamut dimension
  var Int steps1 := shunt steps=defined steps src_gamut:mode
  var Str k := (string src_gamut:name)+" "+string:(src_gamut
  if (cache_open "/pliant/color/conversion/"+k ColorGridConv
    conv compute src_gamut dest_gamut steps1 cached
    conv compute src_gamut dest_gamut steps1 cached cached
    cache_ready ((addressof Link:ColorGridConversion conv) m

    cache_ready ((addressof Link:ColorGridConversion conv) m

export ColorGridConversion '. convert_function' '. convert_name' '. convert_param' '. compute' '. apply'




#-----------------------------------------------------------
#   grid based simulation



method gamut do_formulate color options pixel -> distance
  oarg ColorGamutSubstractive gamut ; arg ColorXYZ color ; a
  var Str opt := options+" "+(gamut query "options")
  (var Array:Int maximum) size := gamut dimension
  for (var Int dim) 0 gamut:dimension-1
    if not ((gamut query "component_maximum "+string:dim) pa
      maximum dim := 255
  var Int limit
  var Float flimit := opt option "limit" Float
  if flimit=defined
    limit := cast flimit*255 Int
  else
    limit := undefined
  var Float l := opt option "cmc_l" Float cmc_distance_l_par
  var Float c := opt option "cmc_c" Float cmc_distance_c_par
  var Float epsilon := opt option "epsilon" Float 0.5
#-----------------------------------------------------------
#   grid based simulation



method gamut do_formulate color options pixel -> distance
  oarg ColorGamutSubstractive gamut ; arg ColorXYZ color ; a
  var Str opt := options+" "+(gamut query "options")
  (var Array:Int maximum) size := gamut dimension
  for (var Int dim) 0 gamut:dimension-1
    if not ((gamut query "component_maximum "+string:dim) pa
      maximum dim := 255
  var Int limit
  var Float flimit := opt option "limit" Float
  if flimit=defined
    limit := cast flimit*255 Int
  else
    limit := undefined
  var Float l := opt option "cmc_l" Float cmc_distance_l_par
  var Float c := opt option "cmc_c" Float cmc_distance_c_par
  var Float epsilon := opt option "epsilon" Float 0.5
  var CBool incremental := opt option "incremental"
  distance := 1e10
  distance := 1e10
  if advanced
  if advanced and not (opt option "conservative")
    part compose
      (var Array:ColorBuffer tests) size := gamut:formulate_
      (var Array:Float distances) size := gamut:formulate_us
      for (var Int i) 0 gamut:formulate_using:size-1
    part compose
      (var Array:ColorBuffer tests) size := gamut:formulate_
      (var Array:Float distances) size := gamut:formulate_us
      for (var Int i) 0 gamut:formulate_using:size-1
        gamut fill_pixel gamut:formulate_using:i:using opt (
        if incremental
          memory_copy pixel (addressof tests:i) gamut:pixel_size
        else
          gamut fill_pixel gamut:formulate_using:i:using opt (addressof tests:i)
        distances i := undefined
      var Float hue := (cast color ColorLCh) h
      var (Index Float Int) combinations
      for (var Int i) 0 gamut:formulate_using:size-1
        if gamut:formulate_using:i:using:size=3
          combinations insert (min (min (abs hue-gamut:formu
      each ii combinations
        distances ii := gamut try_formulate1 color (addresso
        if distances:ii<distance
          memory_copy (addressof tests:ii) pixel gamut:pixel
          if distance<epsilon
            leave compose
      var Float mi := opt option "cmc_maximum_improvement" F
      for (var Int i) 0 gamut:formulate_using:size-1
        if distances:i=undefined or distances:i<distance+mi
          var Float d := gamut try_formulate2 color (address
          if d<distance
            memory_copy (addressof tests:i) pixel gamut:pixe
            if distance<epsilon
              leave compose
  else
    for (var Int i) 0 gamut:formulate_using:size-1
        distances i := undefined
      var Float hue := (cast color ColorLCh) h
      var (Index Float Int) combinations
      for (var Int i) 0 gamut:formulate_using:size-1
        if gamut:formulate_using:i:using:size=3
          combinations insert (min (min (abs hue-gamut:formu
      each ii combinations
        distances ii := gamut try_formulate1 color (addresso
        if distances:ii<distance
          memory_copy (addressof tests:ii) pixel gamut:pixel
          if distance<epsilon
            leave compose
      var Float mi := opt option "cmc_maximum_improvement" F
      for (var Int i) 0 gamut:formulate_using:size-1
        if distances:i=undefined or distances:i<distance+mi
          var Float d := gamut try_formulate2 color (address
          if d<distance
            memory_copy (addressof tests:i) pixel gamut:pixe
            if distance<epsilon
              leave compose
  else
    for (var Int i) 0 gamut:formulate_using:size-1
      gamut fill_pixel gamut:formulate_using:i:using opt add
      var ColorBuffer test
      if incremental
        memory_copy pixel addressof:test gamut:pixel_size
      else
        gamut fill_pixel gamut:formulate_using:i:using opt addressof:test
      var Float d := gamut try_formulate2 color addressof:te
      if d<distance
        memory_copy addressof:test pixel gamut:pixel_size ; 
  if (opt option "removal") and gamut:dimension=4
    if not ((opt (opt option_position "removal" 0) opt:len) 
      b0 := 0 ; b1 := 0
    var Int black := pixel map uInt8 3
    if black>=b1
      void
    eif black<b0
      black := 0
    else
      black := b1*(black-b0)\(b1-b0)
    (var Array:Int using) size := 3
    using 0 := 0 ; using 1 := 1 ; using 2 := 2
    gamut fill_pixel using opt addressof:(var ColorBuffer te
    if advanced
      gamut try_formulate1 color addressof:test using maximu
    d := gamut try_formulate2 color addressof:test using max
    if d<distance or d<epsilon
      memory_copy addressof:test pixel gamut:pixel_size ; di


function color_gamut name options -> g
  arg Str name options ; arg Link:ColorGamut g
  var Pointer:Type t
  if (name parse any:(var Str device) ":" any:(var Str inks)
    t :> ColorGamutSubstractive
  eif name="grey"
    t :> ColorGamut
  eif name="XYZ"
    t :> ColorGamutXYZ
  else
    t :> ColorGamutRGB
  plugin extra_types
  if (cache_open "/pliant/color/gamut/"+string:name+options 
    g name := name
    part build
      if t=ColorGamut
        g pixel_size := 1
        g dimension := 1
        g model := color_gamut_additive
        g status := success
      eif t=ColorGamutRGB
        var Pointer:ColorGamutRGB ga :> addressof:g map Colo
        if name="rgb"
          rgb_gamut ga name 0 0 false options
        eif name="rgb32"
          rgb_gamut ga name 0 1 false options
        eif name="bgr"
          rgb_gamut ga name 0 0 true options
        eif name="bgr32"
          rgb_gamut ga name 0 1 true options
        eif name="rgba"
          rgb_gamut ga name 1 0 false options
        else
          g status := failure
      eif t=ColorGamutXYZ
        g pixel_size := 3*Float32:size
        g dimension := 3
        g model := color_gamut_additive
        g status := success
      eif t=ColorGamutSubstractive
        var Pointer:ColorGamutSubstractive gs :> addressof:g
        gs model := color_gamut_substractive
        gs device := device
        gs extra := options
        gs options := options+(shunt options<>"" and color_d
        gs deaden := gs:options option "deaden" Float 0
        gs no_opacity := gs:options option "no_opacity"
        inks := replace inks "cmyk" "process_cyan+process_ma
        while inks<>""
          if not (inks eparse any:(var Str ink) "+" any:(var
            ink := inks ; remain := ""
          if ink="transparency"
            gs transparency := 1
          eif ink="transparencies"
            gs multiple_transparency := true
          else
            gs:component size := dim+1
            var Pointer:ColorComponent gc :> gs:component di
            gc name := ink
            if (ink eparse any:(var Str base) "#" any)
              ink := base
            gc ink :> color_ink (shunt (ink search ":" -1)=(
            var Int i := 0
            while gc:ink=failure and { var Str device2 := gs
              gc ink :> color_ink device2+":"+ink options
              i += 1
            if gc:ink=failure
              g status := failure (shunt (exists color_datab
              leave build
            if (gc:ink:options option "negative")
              gs negatives += 2^dim
            dim += 1
            if (gc:ink:options option "reverse_printing")
              gs reverse_printing := true
            if (ink search ":" -1)<>(-1) and (gc:ink:options
              gs deaden := gc:ink deaden
          inks := remain
        if gs:multiple_transparency 
          gs transparency := dim
        gs dimension := dim
        gs pixel_size := gs:dimension+gs:transparency
        if (gs:options option "formulate" Str)<>""
          var Int i := 0
          while { var Str inks := gs:options option "formula
            i += 1
            part add_combination
              var ColorFormulateUsing using
              using:using size := 0
              while inks<>""
                if not (inks eparse any:(var Str ink) "+" an
                  ink := inks ; remain := ""
                part seach_ink
                  for (var Int j) 0 gs:dimension-1
      var Float d := gamut try_formulate2 color addressof:te
      if d<distance
        memory_copy addressof:test pixel gamut:pixel_size ; 
  if (opt option "removal") and gamut:dimension=4
    if not ((opt (opt option_position "removal" 0) opt:len) 
      b0 := 0 ; b1 := 0
    var Int black := pixel map uInt8 3
    if black>=b1
      void
    eif black<b0
      black := 0
    else
      black := b1*(black-b0)\(b1-b0)
    (var Array:Int using) size := 3
    using 0 := 0 ; using 1 := 1 ; using 2 := 2
    gamut fill_pixel using opt addressof:(var ColorBuffer te
    if advanced
      gamut try_formulate1 color addressof:test using maximu
    d := gamut try_formulate2 color addressof:test using max
    if d<distance or d<epsilon
      memory_copy addressof:test pixel gamut:pixel_size ; di


function color_gamut name options -> g
  arg Str name options ; arg Link:ColorGamut g
  var Pointer:Type t
  if (name parse any:(var Str device) ":" any:(var Str inks)
    t :> ColorGamutSubstractive
  eif name="grey"
    t :> ColorGamut
  eif name="XYZ"
    t :> ColorGamutXYZ
  else
    t :> ColorGamutRGB
  plugin extra_types
  if (cache_open "/pliant/color/gamut/"+string:name+options 
    g name := name
    part build
      if t=ColorGamut
        g pixel_size := 1
        g dimension := 1
        g model := color_gamut_additive
        g status := success
      eif t=ColorGamutRGB
        var Pointer:ColorGamutRGB ga :> addressof:g map Colo
        if name="rgb"
          rgb_gamut ga name 0 0 false options
        eif name="rgb32"
          rgb_gamut ga name 0 1 false options
        eif name="bgr"
          rgb_gamut ga name 0 0 true options
        eif name="bgr32"
          rgb_gamut ga name 0 1 true options
        eif name="rgba"
          rgb_gamut ga name 1 0 false options
        else
          g status := failure
      eif t=ColorGamutXYZ
        g pixel_size := 3*Float32:size
        g dimension := 3
        g model := color_gamut_additive
        g status := success
      eif t=ColorGamutSubstractive
        var Pointer:ColorGamutSubstractive gs :> addressof:g
        gs model := color_gamut_substractive
        gs device := device
        gs extra := options
        gs options := options+(shunt options<>"" and color_d
        gs deaden := gs:options option "deaden" Float 0
        gs no_opacity := gs:options option "no_opacity"
        inks := replace inks "cmyk" "process_cyan+process_ma
        while inks<>""
          if not (inks eparse any:(var Str ink) "+" any:(var
            ink := inks ; remain := ""
          if ink="transparency"
            gs transparency := 1
          eif ink="transparencies"
            gs multiple_transparency := true
          else
            gs:component size := dim+1
            var Pointer:ColorComponent gc :> gs:component di
            gc name := ink
            if (ink eparse any:(var Str base) "#" any)
              ink := base
            gc ink :> color_ink (shunt (ink search ":" -1)=(
            var Int i := 0
            while gc:ink=failure and { var Str device2 := gs
              gc ink :> color_ink device2+":"+ink options
              i += 1
            if gc:ink=failure
              g status := failure (shunt (exists color_datab
              leave build
            if (gc:ink:options option "negative")
              gs negatives += 2^dim
            dim += 1
            if (gc:ink:options option "reverse_printing")
              gs reverse_printing := true
            if (ink search ":" -1)<>(-1) and (gc:ink:options
              gs deaden := gc:ink deaden
          inks := remain
        if gs:multiple_transparency 
          gs transparency := dim
        gs dimension := dim
        gs pixel_size := gs:dimension+gs:transparency
        if (gs:options option "formulate" Str)<>""
          var Int i := 0
          while { var Str inks := gs:options option "formula
            i += 1
            part add_combination
              var ColorFormulateUsing using
              using:using size := 0
              while inks<>""
                if not (inks eparse any:(var Str ink) "+" an
                  ink := inks ; remain := ""
                part seach_ink
                  for (var Int j) 0 gs:dimension-1
                    if gs:component:i:name=ink
                    if gs:component:j:name=ink
                      using using += j
                      leave seach_ink
                      using using += j
                      leave seach_ink
                  console "formulate using missing ink " ink eol
                  leave add_combination
                  leave add_combination
                inks := remain
              using hue := undefined
              gs formulate_using += using
        eif gs:dimension>=4
          var Int darkest := gs:options option "darkest" Int
          if darkest=undefined
            darkest := 0 ; var Float Ymini := 1e6
            for (var Int i) 0 gs:dimension-1
              var Float Y := (filter_XYZ gs:component:i:ink:
              if Y<Ymini
                darkest := i ; Ymini := Y
          var (Index Float Int) hues
          for (var Int i) 0 gs:dimension-1
            if i<>darkest and not (gs:component:i:ink:option
              hues insert (cast (filter_XYZ gs:component:i:i
          each hue hues
            var Pointer:Int hue2 :> hues next hue
            if not exists:hue2
              hue2 :> hues first
            var ColorFormulateUsing using
            using:using size := 3
            using:using 0 := darkest
            using:using 1 := hue
            using:using 2 := hue2
            var Float h1 := hues key hue
            var Float h2 := hues key hue2
            if h2<h1
              h2 += 360
            var Float h := (h1+h2)/2
            if h>=360
              h -= 360
            using hue := h
            gs formulate_using += using
        else
          gs:formulate_using size := 1
          gs:formulate_using:0:using size := gs dimension
          for (var Int i) 0 gs:formulate_using:0:using:size-
            gs:formulate_using:0:using i := i
          gs:formulate_using:0 hue := undefined
        var Array:FileInfo grids := file_list "data:/pliant/
        for (var Int i) 0 grids:size-1
          (var Stream s) open grids:i:name in+safe
          (var Array:Int indice) size := 0 ; var uInt mask :
          while not s:atend and { var Str l := s readline ; 
            if (l parse word:"ink" (var Str inkname) any:(va
              indice += undefined
              for (var Int j) 0 gs:dimension-1
                if gs:component:j:name=inkname
                  indice indice:size-1 := j
              if (indice indice:size-1)<>undefined
                mask += 2^(indice indice:size-1)
          if bits_count:mask>=2
            var ColorGrid grid
            grid indice := indice
            grid mask := mask
            grid name := device+"/"+grids:i:name_without_pat
            gs grid += grid
        # console "gamut " name " is using " gs:grid:size " 
        for (var Int i) 0 gs:grid:size-1
          gs:grid:i simulation :> color_grid_simulation gs:g
          if not (exists gs:grid:i:simulation)
            g status := failure "Corrupted color grid "+gs:g
            leave build
        gs status := shunt gs:pixel_size<=gamut_maximum_dime
    plugin extra_gamuts
    if g:status=success
      cache_ready ((addressof Link:ColorGamut g) map Link:Ca
    else
      cache_cancel ((addressof Link:ColorGamut g) map Link:C
      var ExtendedStatus status := g status
      g :> new ColorGamut
      g status := status


method g speedup src_gamut options -> speedup
  oarg ColorGamutRGB g src_gamut ; arg Str options ; arg Arr
  if (entry_type addressof:src_gamut)=ColorGamutSubstractive
    speedup := addressof void
  eif src_gamut:model=color_gamut_additive and g:options<>""
    var Link:ColorGridConversion gconv :> new ColorGridConve
              using hue := undefined
              gs formulate_using += using
        eif gs:dimension>=4
          var Int darkest := gs:options option "darkest" Int
          if darkest=undefined
            darkest := 0 ; var Float Ymini := 1e6
            for (var Int i) 0 gs:dimension-1
              var Float Y := (filter_XYZ gs:component:i:ink:
              if Y<Ymini
                darkest := i ; Ymini := Y
          var (Index Float Int) hues
          for (var Int i) 0 gs:dimension-1
            if i<>darkest and not (gs:component:i:ink:option
              hues insert (cast (filter_XYZ gs:component:i:i
          each hue hues
            var Pointer:Int hue2 :> hues next hue
            if not exists:hue2
              hue2 :> hues first
            var ColorFormulateUsing using
            using:using size := 3
            using:using 0 := darkest
            using:using 1 := hue
            using:using 2 := hue2
            var Float h1 := hues key hue
            var Float h2 := hues key hue2
            if h2<h1
              h2 += 360
            var Float h := (h1+h2)/2
            if h>=360
              h -= 360
            using hue := h
            gs formulate_using += using
        else
          gs:formulate_using size := 1
          gs:formulate_using:0:using size := gs dimension
          for (var Int i) 0 gs:formulate_using:0:using:size-
            gs:formulate_using:0:using i := i
          gs:formulate_using:0 hue := undefined
        var Array:FileInfo grids := file_list "data:/pliant/
        for (var Int i) 0 grids:size-1
          (var Stream s) open grids:i:name in+safe
          (var Array:Int indice) size := 0 ; var uInt mask :
          while not s:atend and { var Str l := s readline ; 
            if (l parse word:"ink" (var Str inkname) any:(va
              indice += undefined
              for (var Int j) 0 gs:dimension-1
                if gs:component:j:name=inkname
                  indice indice:size-1 := j
              if (indice indice:size-1)<>undefined
                mask += 2^(indice indice:size-1)
          if bits_count:mask>=2
            var ColorGrid grid
            grid indice := indice
            grid mask := mask
            grid name := device+"/"+grids:i:name_without_pat
            gs grid += grid
        # console "gamut " name " is using " gs:grid:size " 
        for (var Int i) 0 gs:grid:size-1
          gs:grid:i simulation :> color_grid_simulation gs:g
          if not (exists gs:grid:i:simulation)
            g status := failure "Corrupted color grid "+gs:g
            leave build
        gs status := shunt gs:pixel_size<=gamut_maximum_dime
    plugin extra_gamuts
    if g:status=success
      cache_ready ((addressof Link:ColorGamut g) map Link:Ca
    else
      cache_cancel ((addressof Link:ColorGamut g) map Link:C
      var ExtendedStatus status := g status
      g :> new ColorGamut
      g status := status


method g speedup src_gamut options -> speedup
  oarg ColorGamutRGB g src_gamut ; arg Str options ; arg Arr
  if (entry_type addressof:src_gamut)=ColorGamutSubstractive
    speedup := addressof void
  eif src_gamut:model=color_gamut_additive and g:options<>""
    var Link:ColorGridConversion gconv :> new ColorGridConve
    gconv compute src_gamut g (min (max (g:options option "g
    gconv compute src_gamut g (min (max (g:options option "grid_steps" Int 17) 5) 65) false false
    if hash_rgb
      var Link:ColorSplitConversion sconv :> color_split_con
      speedup := addressof sconv
    else
      speedup := addressof gconv
  else
    speedup := null



function color_gamut_profile src_gamut_name dest_gamut_name 
  arg Str src_gamut_name dest_gamut_name filename ; arg Int 
  var Link:ColorGamut src_gamut :> color_gamut src_gamut_nam
  var Link:ColorGamut dest_gamut :> color_gamut dest_gamut_n
  var Link:ColorGridConversion conv :> new ColorGridConversi
  var Int dim := src_gamut:dimension
  var Int default_steps := shunt dim<=3 and src_gamut:model=
    if hash_rgb
      var Link:ColorSplitConversion sconv :> color_split_con
      speedup := addressof sconv
    else
      speedup := addressof gconv
  else
    speedup := null



function color_gamut_profile src_gamut_name dest_gamut_name 
  arg Str src_gamut_name dest_gamut_name filename ; arg Int 
  var Link:ColorGamut src_gamut :> color_gamut src_gamut_nam
  var Link:ColorGamut dest_gamut :> color_gamut dest_gamut_n
  var Link:ColorGridConversion conv :> new ColorGridConversi
  var Int dim := src_gamut:dimension
  var Int default_steps := shunt dim<=3 and src_gamut:model=
  conv compute src_gamut dest_gamut (shunt steps=defined ste
  conv compute src_gamut dest_gamut (shunt steps=defined steps default_steps) true true
  conv dump filename src_gamut dest_gamut


export color_gamut_compute color_gamut_profile
  conv dump filename src_gamut dest_gamut


export color_gamut_compute color_gamut_profile