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


constant hash_conversion true
constant hash_rgb true
abstract
  ['ColorGamut' data type is defining how a pixel is encoded


constant hash_conversion true
constant hash_rgb true
constant screen_option false






  method g formulate color options pixel
    oarg ColorGamut g ; arg ColorXYZ color ; arg Str options ; arg Address pixel
    generic

  method g formulate color pixel
    oarg ColorGamut g ; arg ColorXYZ color ; arg Address pix
  method g formulate color pixel
    oarg ColorGamut g ; arg ColorXYZ color ; arg Address pix
    generic
    g formulate color "" pixel




method g formulate color pixel
  oarg ColorGamutRGB g ; arg ColorXYZ color ; arg Address pi
method g formulate color options pixel
  oarg ColorGamutRGB g ; arg ColorXYZ color ; arg Str options ; arg Address pixel
  var ColorRGB888 rgb := cast color ColorRGB888
  if g:reversed
    for (var Int c) 0 2
      pixel map uInt8 c := addressof:rgb map uInt8 2-c
  else
    pixel map ColorRGB888 := rgb



type ColorGamutSubstractive
  inherit ColorGamut
  field Array:ColorComponent component
  field Str device options
  var ColorRGB888 rgb := cast color ColorRGB888
  if g:reversed
    for (var Int c) 0 2
      pixel map uInt8 c := addressof:rgb map uInt8 2-c
  else
    pixel map ColorRGB888 := rgb



type ColorGamutSubstractive
  inherit ColorGamut
  field Array:ColorComponent component
  field Str device options
  field Float specular <- 0
  field Float deaden <- 0
  if screen_option
    field CBool screen <- false
  field CBool multiple_transparency <- false
  field CBool no_opacity <- false
  field CBool reverse_printing <- false
  field Int negatives <- 0
  
ColorGamut maybe ColorGamutSubstractive



  field CBool multiple_transparency <- false
  field CBool no_opacity <- false
  field CBool reverse_printing <- false
  field Int negatives <- 0
  
ColorGamut maybe ColorGamutSubstractive



method gamut apply_deaden pixel filter
  arg ColorGamutSubstractive gamut ; arg Address pixel ; arg
  var Float total := 0 ; var Float maxi := 0
  for (var Int i) 0 gamut:dimension-1
    var Pointer:ColorInk ink :> gamut:component:i ink
    var Float d := ink:gradation decode (pixel map uInt8 i)
    var Float deaden := d*ink:deaden
    total += deaden ; maxi := max maxi deaden
  if total>maxi
    filter += cast total-maxi ColorSpectrum32

method gamut simulate2 pixel -> filter
  oarg ColorGamutSubstractive gamut ; arg Address pixel ; ar
  part simulate "substractive color simulation "+gamut:name
    var ColorBuffer pixel2
    if gamut:no_opacity
      memory_copy pixel addressof:pixel2 gamut:pixel_size
    else
      gamut apply_opacity pixel addressof:pixel2
method gamut simulate2 pixel -> filter
  oarg ColorGamutSubstractive gamut ; arg Address pixel ; ar
  part simulate "substractive color simulation "+gamut:name
    var ColorBuffer pixel2
    if gamut:no_opacity
      memory_copy pixel addressof:pixel2 gamut:pixel_size
    else
      gamut apply_opacity pixel addressof:pixel2
    var ColorBuffer plus_buffer minus_buffer
    var Address plus minus
    if gamut:component:size<=gamut_maximum_dimension
      plus := addressof plus_buffer ; minus := addressof min
    else
      plus := memory_allocate gamut:component:size null ; mi
    gamut dispatch_pixel addressof:pixel2 plus minus
    if white_mapping
      filter := cast 1 ColorSpectrum32
    else
      var Pointer:ColorSpectrum32 s0 :> gamut:component:0:in
      var Float Y0 := illuminant_spectrum*s0 Y
      filter := (1/Y0)*s0
    if white_mapping
      filter := cast 1 ColorSpectrum32
    else
      var Pointer:ColorSpectrum32 s0 :> gamut:component:0:in
      var Float Y0 := illuminant_spectrum*s0 Y
      filter := (1/Y0)*s0
    var Int negatives := gamut negatives
    for (var Int i) 0 gamut:component:size-1
      var Int p := plus map uInt8 i
      var Int m := minus map uInt8 i
      var CBool positive := (negatives .and. 2^i)=0
      if (shunt positive p>m p<>255)
        var Pointer:ColorComponent c :> gamut:component:i
        if m=0
          filter *= c:ink:filter p
    if screen_option and gamut:screen
      var (Array Int gamut_maximum_dimension) dim
      var (Array Float gamut_maximum_dimension) dens
      var Int n := 0
      for (var Int d) 0 gamut:dimension-1
        var Int v := addressof:pixel2 map uInt8 d
        var Pointer:ColorComponent c :> gamut:component d
        if v=0
          filter *= c:ink f0
        eif v=255
          filter *= c:ink f100
        else
        else
          check positive
          filter := filter*(c:ink:filter p)/(c:ink:filter m)
    gamut apply_deaden pixel filter
    if gamut:component:size>gamut_maximum_dimension
      memory_free plus ; memory_free minus
          dim n := d
          dens n := c:ink:gradation:decode_table v
          n += 1
      var ColorSpectrum32 sum := cast 0 ColorSpectrum32
      for (var Int u) 0 3^n-1
        var Float w := 1 ; var ColorSpectrum32 f := filter
        for (var Int d) 0 n-1
          var Pointer:ColorComponent c :> gamut:component dim:d
          var Int r := u \ 3^d % 3
          if r=0
            w *= (1-dens:d)*(1-dens:d) ; f *= c:ink f0
          eif r=1
            w *= 2*dens:d*(1-dens:d) ; f *= c:ink f50
          else
            w *= dens:d*dens:d ; f *= c:ink f100
        sum += w*f
      filter := sum
    else
      var ColorBuffer plus_buffer minus_buffer
      var Address plus minus
      if gamut:component:size<=gamut_maximum_dimension
        plus := addressof plus_buffer ; minus := addressof minus_buffer
      else
        plus := memory_allocate gamut:component:size null ; minus := memory_allocate gamut:component:size null
      gamut dispatch_pixel addressof:pixel2 plus minus
      var CBool has_deaden := gamut:deaden>0
      if has_deaden
        var ColorSpectrum32 strongest := cast 1 ColorSpectrum32
      var Int negatives := gamut negatives
      for (var Int i) 0 gamut:component:size-1
        var Int p := plus map uInt8 i
        var Int m := minus map uInt8 i
        var CBool positive := (negatives .and. 2^i)=0
        if (shunt positive p>m p<>255)
          var Pointer:ColorComponent c :> gamut:component:i
          if m=0
            filter *= c:ink:filter p
            if has_deaden
              strongest := min strongest c:ink:filter:p
          eif has_deaden
            check positive
            var ColorSpectrum32 fi := (c:ink:filter p)/(c:ink:filter m)
            filter *= fi
            strongest := min strongest fi
          else
            check positive
            filter := filter*(c:ink:filter p)/(c:ink:filter m)
      if has_deaden
        filter := strongest*(filter/strongest)^(1/(1+gamut:deaden))
      if gamut:component:size>gamut_maximum_dimension
        memory_free plus ; memory_free minus
    if gamut:specular>0
      filter := (1-gamut:specular)*filter+(cast gamut:specular ColorSpectrum32)




function distance c1 c2 -> d
  arg ColorXYZ c1 c2 ; arg Float d
  d := cmc_distance c1 c2


method gamut try_formulate wished pixel using -> distance
  oarg ColorGamut gamut ; arg ColorXYZ wished ; arg Address 
method gamut try_formulate wished pixel using l c -> distance
  oarg ColorGamut gamut ; arg ColorXYZ wished ; arg Address pixel ; arg Array:Int using ; arg Float l c ; arg Float distance
  (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 := (gamut query "options") option "limit"
  if flimit=defined
    limit := cast flimit*255 Int
  else
    limit := undefined
  var Int dimension := using size
  (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 := (gamut query "options") option "limit"
  if flimit=defined
    limit := cast flimit*255 Int
  else
    limit := undefined
  var Int dimension := using size
  distance := distance wished (gamut simulate pixel)
  distance := cmc_distance wished (gamut simulate pixel) l c
  var Int step := 4 ; var CBool again := true
  while step>0
    again := false
    memory_copy pixel addressof:(var ColorBuffer pixel2) gam
    for (var Int i) 0 3^dimension-1
      part try_one
        memory_copy pixel addressof:(var ColorBuffer pixel1)
        var Int ii := i
        for (var Int dim) 0 dimension-1
          var Int d := using dim
          var Int delta := ii%3-1 ; ii \= 3
          if delta<0
            if pixel1:bytes:d<step
              leave try_one
            pixel1:bytes d -= step
          eif delta>0
            if pixel1:bytes:d+step>maximum:d
              leave try_one
            pixel1:bytes d += step
        if limit=defined
          var Int total := 0
          for (var Int d) 0 gamut:dimension-1
            total += pixel1:bytes d
          if total>limit
            leave try_one
  var Int step := 4 ; var CBool again := true
  while step>0
    again := false
    memory_copy pixel addressof:(var ColorBuffer pixel2) gam
    for (var Int i) 0 3^dimension-1
      part try_one
        memory_copy pixel addressof:(var ColorBuffer pixel1)
        var Int ii := i
        for (var Int dim) 0 dimension-1
          var Int d := using dim
          var Int delta := ii%3-1 ; ii \= 3
          if delta<0
            if pixel1:bytes:d<step
              leave try_one
            pixel1:bytes d -= step
          eif delta>0
            if pixel1:bytes:d+step>maximum:d
              leave try_one
            pixel1:bytes d += step
        if limit=defined
          var Int total := 0
          for (var Int d) 0 gamut:dimension-1
            total += pixel1:bytes d
          if total>limit
            leave try_one
        var Float dist1 := distance wished (gamut simulate a
        var Float dist1 := cmc_distance wished (gamut simulate addressof:pixel1) l c
        if dist1<distance
          memory_copy addressof:pixel1 addressof:pixel2 gamu
          again := true
    memory_copy addressof:pixel2 pixel gamut:pixel_size
    if not again
      step -= 1 ; again := true

method gamut fill_pixel pixel
  oarg ColorGamutSubstractive gamut ; arg Address pixel
  memory_clear pixel gamut:pixel_size
  for (var Int i) 0 gamut:dimension-1
        if dist1<distance
          memory_copy addressof:pixel1 addressof:pixel2 gamu
          again := true
    memory_copy addressof:pixel2 pixel gamut:pixel_size
    if not again
      step -= 1 ; again := true

method gamut fill_pixel pixel
  oarg ColorGamutSubstractive gamut ; arg Address pixel
  memory_clear pixel gamut:pixel_size
  for (var Int i) 0 gamut:dimension-1
    if (gamut:options option "initial"+string:i)
      pixel map uInt8 i := cast (gamut:options option "initi
    var Str ink := gamut query "component_name "+string:i
    if (gamut:options option "initial_"+ink)
      pixel map uInt8 i := cast (gamut:options option "initial_"+ink Float)*255 Int


method gamut try_formulate color pixel b0 b1 -> distance
  oarg ColorGamutSubstractive gamut ; arg ColorXYZ color ; a
method gamut formulate color options pixel
  oarg ColorGamutSubstractive gamut ; arg ColorXYZ color ; arg Str options ; arg Address pixel
  var Str opt := options+" "+(gamut query "options")
  if not ((opt (options option_position "removal" 0) options:len) parse word:"removal" (var Int b0) (var Int b1) any)
    b0 := 0 ; b1 := 0
  var Float epsilon := opt option "epsilon" Float 0.5
  var Float l := opt option "l" Float cmc_distance_l_parameter
  var Float c := opt option "c" Float cmc_distance_c_parameter
  if gamut:dimension>=4
  if gamut:dimension>=4
    distance := 1e10
    (var Array:Int using) size := 3 ; using 2 := 3
    var Int darkest := opt option "darkest" Int
    if darkest=undefined
      darkest := 0 ; var Float Ymini := 1e6
      for (var Int i) 0 gamut:dimension-1
        var Float Y := (filter_XYZ gamut:component:i:ink:s100/gamut:component:i:ink:s0) Y
        if Y<Ymini
          darkest := i ; Ymini := Y
    var Float distance := 1e10
    (var Array:Int using) size := 3 ; using 2 := darkest
    for using:0 0 gamut:dimension-1
      for using:1 using:0+1 gamut:dimension-1
    for using:0 0 gamut:dimension-1
      for using:1 using:0+1 gamut:dimension-1
        if using:0<>3 and using:1<>3
        if using:0<>darkest and using:1<>darkest
          memory_clear addressof:(var ColorBuffer test) gamu
          memory_clear addressof:(var ColorBuffer test) gamu
          var Float d := gamut try_formulate color addressof
          var Float d := gamut try_formulate color addressof:test using l c
          if d<distance
            memory_copy addressof:test pixel gamut:pixel_siz
          if d<distance
            memory_copy addressof:test pixel gamut:pixel_siz
    using 0 := 0 ; using 1 := 1 ; using 2 := 2
    memory_clear addressof:test gamut:pixel_size ; test:byte
    var Float d := gamut try_formulate color addressof:test 
    if d<distance
      memory_copy addressof:test pixel gamut:pixel_size ; di
    var Int black := pixel map uInt8 3
    if black>=b1
      void
    eif black<b0
      black := 0
    else
      black := b1*(black-b0)\(b1-b0)
    gamut fill_pixel addressof:test ; test:bytes 3 := black
    using 0 := 0 ; using 1 := 1 ; using 2 := 2
    d := gamut try_formulate color addressof:test using
    if d<distance
      memory_copy addressof:test pixel gamut:pixel_size ; di
    if (options option "removal") and gamut:dimension=4 and darkest=3
      using 0 := 0 ; using 1 := 1 ; using 2 := 2
      memory_clear addressof:test gamut:pixel_size ; test:bytes 3 := 255
      var Float d := gamut try_formulate color addressof:test using l c
      if d<distance
        memory_copy addressof:test pixel gamut:pixel_size ; distance := d
      var Int black := pixel map uInt8 3
      if black>=b1
        void
      eif black<b0
        black := 0
      else
        black := b1*(black-b0)\(b1-b0)
      gamut fill_pixel addressof:test ; test:bytes 3 := black
      using 0 := 0 ; using 1 := 1 ; using 2 := 2
      d := gamut try_formulate color addressof:test using l c
      if d<distance or d<epsilon
        memory_copy addressof:test pixel gamut:pixel_size ; distance := d
  else
    gamut fill_pixel pixel
    (var Array:Int using) size := gamut dimension
    for (var Int i) 0 using:size-1
      using i := i
  else
    gamut fill_pixel pixel
    (var Array:Int using) size := gamut dimension
    for (var Int i) 0 using:size-1
      using i := i
    distance := gamut try_formulate color pixel using
    gamut try_formulate color pixel using l c


method gamut formulate color pixel
  oarg ColorGamutSubstractive gamut ; arg ColorXYZ color ; a
  part formulate "substractive color formulation "+gamut:nam
    var Str options := gamut query "options"
    if not ((options (options option_position "removal" 0) o
      b0 := 0 ; b1 := 0
    var Float delta := options option "delta" Float 1e10
    var Float d := gamut try_formulate color pixel b0 b1
    if d>delta
      var ColorXYZn xyzn := cast color ColorXYZn
      xyzn Y := bound xyzn:Y 1/16 1-1/16 ; xyzn X := xyzn Y 
      var ColorXYZ grey := cast xyzn ColorXYZ
      var Float desat := 0.5 ; var Float step := 0.25
      while step>0.001
        var ColorXYZ middle
        middle X := color:X*(1-desat)+grey:X*desat
        middle Y := color:Y*(1-desat)+grey:Y*desat
        middle Z := color:Z*(1-desat)+grey:Z*desat
        var Float d := gamut try_formulate middle pixel b0 b
        if d<delta+16*step
          desat -= step
        else
          desat += step
        desat := bound desat 0 1
        step *= 2/3
      if desat>=0.5
        var ColorLCh lch := cast color ColorLCh
        console "color calibration oops: desaturation is " (



method g query question -> answer
  oarg ColorGamutSubstractive g ; arg Str question answer
  if (question parse word:"component_name" (var Int i)) and 
    answer := g:component:i name
  eif (question parse word:"component_maximum" (var Int i)) 
    answer := string g:component:i:ink:maximum
  eif (question parse word:"component_options" (var Int i)) 
    answer := g:component:i:ink options
  eif question="options"
    answer := g options
  eif question="signature"
    answer := g:options+(shunt g:no_opacity " no_opacity" ""
    for (var Int i) 0 g:dimension-1
      answer += " "+(string g:component:i:name)+" "+(string 
  else
    answer := ""



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
  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=ColorGamutSubstractive
        var Pointer:ColorGamutSubstractive gs :> addressof:g
        gs model := color_gamut_substractive
        inks := replace inks "cmyk" "process_cyan+process_ma
        while inks<>""
          if not (inks parse 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 parse any:(var Str base) "#" any)
              ink := base
            gc ink :> color_ink (shunt (ink search ":" -1)=(
            if gc:ink=failure
              g status := failure (shunt (exists color_datab
              leave build
            gc mask := 2^dim
            if (gc:ink:options option "negative")
              gs negatives += 2^dim
            dim += 1
            if (gc:ink:options option "reverse_printing")
              gs reverse_printing := true
          inks := remain
        if gs:multiple_transparency 
          gs transparency := dim
        gs dimension := dim
        gs pixel_size := gs:dimension+gs:transparency
        var Str opt := options+" "+color_database:data:devic
method g query question -> answer
  oarg ColorGamutSubstractive g ; arg Str question answer
  if (question parse word:"component_name" (var Int i)) and 
    answer := g:component:i name
  eif (question parse word:"component_maximum" (var Int i)) 
    answer := string g:component:i:ink:maximum
  eif (question parse word:"component_options" (var Int i)) 
    answer := g:component:i:ink options
  eif question="options"
    answer := g options
  eif question="signature"
    answer := g:options+(shunt g:no_opacity " no_opacity" ""
    for (var Int i) 0 g:dimension-1
      answer += " "+(string g:component:i:name)+" "+(string 
  else
    answer := ""



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
  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=ColorGamutSubstractive
        var Pointer:ColorGamutSubstractive gs :> addressof:g
        gs model := color_gamut_substractive
        inks := replace inks "cmyk" "process_cyan+process_ma
        while inks<>""
          if not (inks parse 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 parse any:(var Str base) "#" any)
              ink := base
            gc ink :> color_ink (shunt (ink search ":" -1)=(
            if gc:ink=failure
              g status := failure (shunt (exists color_datab
              leave build
            gc mask := 2^dim
            if (gc:ink:options option "negative")
              gs negatives += 2^dim
            dim += 1
            if (gc:ink:options option "reverse_printing")
              gs reverse_printing := true
          inks := remain
        if gs:multiple_transparency 
          gs transparency := dim
        gs dimension := dim
        gs pixel_size := gs:dimension+gs:transparency
        var Str opt := options+" "+color_database:data:devic
        if not (opt option "nocomposed")
        if (opt option "composed")
          each ch color_database:data:device:device:channel 
            if (keyof:ch search "+" -1)<>(-1)
              gs add_component device+":" keyof:ch
        gs device := device
        gs options := color_database:data:device:device opti
          each ch color_database:data:device:device:channel 
            if (keyof:ch search "+" -1)<>(-1)
              gs add_component device+":" keyof:ch
        gs device := device
        gs options := color_database:data:device:device opti
        gs specular := gs:options option "final_specular" Float (gs:options option "specular" Float 0)
        gs deaden := gs:options option "deaden" Float 0
        if screen_option
          gs screen := gs:options option "screen"
        gs no_opacity := options option "no_opacity"
        gs status := success
    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
        gs no_opacity := options option "no_opacity"
        gs status := success
    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 :> new ColorGamut
      g status := status




constant grid_conversion_release 10
constant grid_conversion_release 11
constant grid_conversion_cache 16



function color_split_conversion src_gamut dest_gamut device 
  oarg ColorGamut src_gamut dest_gamut ; arg Data:ColorDevic
  conv :> new ColorSplitConversion
  if exists:grid
    var ColorPartConversion part
    part grid :> grid
    conv part += part
    conv single := true
  else
    # check (entry_type addressof:src_gamut)=ColorGamutSubst
    for (var Int i) 0 src_gamut:dimension-1
      var Pointer:ColorInk ink1 :> (addressof:src_gamut map 
      if ink1:opacity=defined and ink1:opacity>0
        conv opacity := true
    var (Dictionary Str Int) component
    for (var Int i) 0 src_gamut:dimension-1
      component insert (src_gamut query "component_name "+st
    while component:size>0
      var Int best_count := 0 ; var Str best_grid ; var Int 
      if (options option "grid" Str)<>""
        var Str all := options option "grid" Str ; var Int c
        while all<>""
          if not (all parse any:(var Str ink) "+" any:(var S
            ink := all ; remain := ""
          if exists:(component first ink)
            count += 1
          all := remain
        best_count := count ; best_grid := options option "g
      if best_count<2
        each g device:grid
          var Str all := keyof g ; var Int count := 0
          while all<>""
            if not (all parse any:(var Str ink) "+" any:(var
              ink := all ; remain := ""
            if exists:(component first ink)
              count += 1
            all := remain
          if count>best_count
            best_count := count ; best_grid := keyof g ; bes
      if best_count>1
constant grid_conversion_cache 16



function color_split_conversion src_gamut dest_gamut device 
  oarg ColorGamut src_gamut dest_gamut ; arg Data:ColorDevic
  conv :> new ColorSplitConversion
  if exists:grid
    var ColorPartConversion part
    part grid :> grid
    conv part += part
    conv single := true
  else
    # check (entry_type addressof:src_gamut)=ColorGamutSubst
    for (var Int i) 0 src_gamut:dimension-1
      var Pointer:ColorInk ink1 :> (addressof:src_gamut map 
      if ink1:opacity=defined and ink1:opacity>0
        conv opacity := true
    var (Dictionary Str Int) component
    for (var Int i) 0 src_gamut:dimension-1
      component insert (src_gamut query "component_name "+st
    while component:size>0
      var Int best_count := 0 ; var Str best_grid ; var Int 
      if (options option "grid" Str)<>""
        var Str all := options option "grid" Str ; var Int c
        while all<>""
          if not (all parse any:(var Str ink) "+" any:(var S
            ink := all ; remain := ""
          if exists:(component first ink)
            count += 1
          all := remain
        best_count := count ; best_grid := options option "g
      if best_count<2
        each g device:grid
          var Str all := keyof g ; var Int count := 0
          while all<>""
            if not (all parse any:(var Str ink) "+" any:(var
              ink := all ; remain := ""
            if exists:(component first ink)
              count += 1
            all := remain
          if count>best_count
            best_count := count ; best_grid := keyof g ; bes
      if best_count>1
        console "  conversion grid "  best_grid eol
        var ColorPartConversion part
        part:mapping size := 0
        var Str all := best_grid
        while all<>""
          if not (all parse any:(var Str ink) "+" any:(var S
            ink := all ; remain := ""
          if exists:(component first ink)
            part mapping += component first ink
            component -= component first ink
          else
            part mapping += undefined
          all := remain
        part gamut :> color_gamut keyof:device+":"+best_grid
        if part:gamut=failure
          console "Incorrect gamut " keyof:device+":"+best_g
          conv :> null map ColorSplitConversion
          return
        part grid :> color_grid_conversion part:gamut dest_g
        conv part += part
      else
        each comp component
          var ColorPartConversion part
          part:mapping size := 1
          part:mapping 0 := comp
          part gamut :> color_gamut keyof:device+":"+(compon
          if part:gamut=failure
            console "Incorrect gamut " keyof:device+":"+(com
            conv :> null map ColorSplitConversion
            return
          part grid :> color_grid_conversion part:gamut dest
          conv part += part
        component := var (Dictionary Str Int) empty_dict
  conv limit := (dest_gamut query "options") option "limit" 
  if hash_conversion
    conv cache_size := options option "hash" Int 63541
    conv cache_buffer := memory_zallocate conv:cache_size*(u



export color_gamut_compute color_gamut_profile
        var ColorPartConversion part
        part:mapping size := 0
        var Str all := best_grid
        while all<>""
          if not (all parse any:(var Str ink) "+" any:(var S
            ink := all ; remain := ""
          if exists:(component first ink)
            part mapping += component first ink
            component -= component first ink
          else
            part mapping += undefined
          all := remain
        part gamut :> color_gamut keyof:device+":"+best_grid
        if part:gamut=failure
          console "Incorrect gamut " keyof:device+":"+best_g
          conv :> null map ColorSplitConversion
          return
        part grid :> color_grid_conversion part:gamut dest_g
        conv part += part
      else
        each comp component
          var ColorPartConversion part
          part:mapping size := 1
          part:mapping 0 := comp
          part gamut :> color_gamut keyof:device+":"+(compon
          if part:gamut=failure
            console "Incorrect gamut " keyof:device+":"+(com
            conv :> null map ColorSplitConversion
            return
          part grid :> color_grid_conversion part:gamut dest
          conv part += part
        component := var (Dictionary Str Int) empty_dict
  conv limit := (dest_gamut query "options") option "limit" 
  if hash_conversion
    conv cache_size := options option "hash" Int 63541
    conv cache_buffer := memory_zallocate conv:cache_size*(u



export color_gamut_compute color_gamut_profile