Patch title: Release 92 bulk changes
Abstract:
File: /graphic/filter/escp2.pli
Key:
    Removed line
    Added line
   
# Copyright  Hubert Tonneau  hubert.tonneau@pliant.cx
#
# Writing this driver was possible only thanks to the great 
# Robert L Krawitz to gather and document detailed informati
# Epson inkjet printers.


constant packbits true
constant heads_count 8
constant matrix_mini 192
constant matrix_maxi 384
constant matrix_release 1
constant top_enhancement true
# Copyright  Hubert Tonneau  hubert.tonneau@pliant.cx
#
# Writing this driver was possible only thanks to the great 
# Robert L Krawitz to gather and document detailed informati
# Epson inkjet printers.


constant packbits true
constant heads_count 8
constant matrix_mini 192
constant matrix_maxi 384
constant matrix_release 1
constant top_enhancement true
constant verbose true
constant verbose false


method f open s options h -> status
  arg_rw ImageWriteFilterEscp2 f ; arg_rw Stream s ; arg Str
  # send printer setup commands, and copy the values we will
  if h:gamut:dimension<>1 and h:gamut:dimension<>3 and h:gam
    return failure:"Only black and white or CMY or CMYK imag
  var Int dpi_x dpi_y base_unit page_unit
  var Int heads jets dot_size bpc dot_levels space_x space_y
  var Int dpi_shift ; var Array:Int shift
  var Float page_x := undefined ; var Float page_y := undefi
  var Str command
  dpi_x := options option "escp2_dpi_x" Int (cast h:size_x/(
  dpi_y := options option "escp2_dpi_y" Int (cast h:size_y/(
  if (dpi_x%360<>0 or dpi_y%360<>0) and not (options option 
    return (failure "Incorrect resolution "+string:dpi_x+" x
  base_unit := options option "escp2_base_unit" Int (max (ma
  page_unit := options option "escp2_page_unit" Int (max (ma
  var Str model := options option "model" Str
  if model=""
    return failure:"You must specify the printer model"
  if model="Epson C80" or model="Epson C82"
    heads := 0Fh
    jets := shunt h:gamut:dimension=1 180 60
    dot_size := 12h
    if h:gamut:dimension<>1
      dpi_shift := 180 ; shift += 120 ; shift += 60 ; shift 
    space_x := dpi_x\360
    space_y := dpi_y\180
    page_x := 210
    page_y := 297
    command := ""
  eif model="Epson 750"
    heads := 3Fh
    jets := 48
    dot_size := 10h
    space_x := dpi_x\360
    space_y := dpi_y\120
    page_x := 210
    page_y := 297
    command := ""
  eif model="Epson 1280" or model="Epson 1290"
    heads := 3Fh
    jets := 48
    dot_size := 10h
    space_x := dpi_x\360
    space_y := dpi_y\120
    page_x := 13*25.4
    page_y := 19*25.4
    command := "coord4 zero_margin roll"
  eif model="Epson 2100" or model="Epson 2200"
    heads := 0BFh
    jets := 96
    dot_size := 10h
    if h:gamut:dimension<>1
      dpi_shift := 360 ; shift += 0 ; shift += 0 ; shift += 
    space_x := dpi_x\360
    space_y := dpi_y\180
    page_x := 13*25.4
    page_y := 19*25.4
    command := "coord4 zero_margin roll co_cutter"
  eif model="Epson 3000"
    heads := 0Fh
    jets := shunt h:gamut:dimension=1 128 64
    dot_size := 1
    space_x := dpi_x\360
    space_y := dpi_y\180
    page_x := 17*25.4
    page_y := 44*25.4
    command := "old"


method f open s options h -> status
  arg_rw ImageWriteFilterEscp2 f ; arg_rw Stream s ; arg Str
  # send printer setup commands, and copy the values we will
  if h:gamut:dimension<>1 and h:gamut:dimension<>3 and h:gam
    return failure:"Only black and white or CMY or CMYK imag
  var Int dpi_x dpi_y base_unit page_unit
  var Int heads jets dot_size bpc dot_levels space_x space_y
  var Int dpi_shift ; var Array:Int shift
  var Float page_x := undefined ; var Float page_y := undefi
  var Str command
  dpi_x := options option "escp2_dpi_x" Int (cast h:size_x/(
  dpi_y := options option "escp2_dpi_y" Int (cast h:size_y/(
  if (dpi_x%360<>0 or dpi_y%360<>0) and not (options option 
    return (failure "Incorrect resolution "+string:dpi_x+" x
  base_unit := options option "escp2_base_unit" Int (max (ma
  page_unit := options option "escp2_page_unit" Int (max (ma
  var Str model := options option "model" Str
  if model=""
    return failure:"You must specify the printer model"
  if model="Epson C80" or model="Epson C82"
    heads := 0Fh
    jets := shunt h:gamut:dimension=1 180 60
    dot_size := 12h
    if h:gamut:dimension<>1
      dpi_shift := 180 ; shift += 120 ; shift += 60 ; shift 
    space_x := dpi_x\360
    space_y := dpi_y\180
    page_x := 210
    page_y := 297
    command := ""
  eif model="Epson 750"
    heads := 3Fh
    jets := 48
    dot_size := 10h
    space_x := dpi_x\360
    space_y := dpi_y\120
    page_x := 210
    page_y := 297
    command := ""
  eif model="Epson 1280" or model="Epson 1290"
    heads := 3Fh
    jets := 48
    dot_size := 10h
    space_x := dpi_x\360
    space_y := dpi_y\120
    page_x := 13*25.4
    page_y := 19*25.4
    command := "coord4 zero_margin roll"
  eif model="Epson 2100" or model="Epson 2200"
    heads := 0BFh
    jets := 96
    dot_size := 10h
    if h:gamut:dimension<>1
      dpi_shift := 360 ; shift += 0 ; shift += 0 ; shift += 
    space_x := dpi_x\360
    space_y := dpi_y\180
    page_x := 13*25.4
    page_y := 19*25.4
    command := "coord4 zero_margin roll co_cutter"
  eif model="Epson 3000"
    heads := 0Fh
    jets := shunt h:gamut:dimension=1 128 64
    dot_size := 1
    space_x := dpi_x\360
    space_y := dpi_y\180
    page_x := 17*25.4
    page_y := 44*25.4
    command := "old"
  eif model="Epson 4000"
    heads := 0BFh
    jets := 1
    dot_size := 12h
    space_x := 1
    space_y := 1
    page_x := 17*25.4
    page_y := 44*25.4
    command := "coord4 roll ac_cutter"
  eif model="Epson 7600" or model="Epson 9600" or model="Eps
    heads := shunt model="Epson 10600" 03Fh 0BFh
    jets := 1
    dot_size := 10h
    space_x := 1
    space_y := 1
    command := "coord4 roll ac_cutter"
  else
    return (failure "'"+model+"' is not a valid printer mode
  command := options option "escp2_command" Str command
  var CBool old := command option "old"
  var CBool coord4 := command option "coord4"
  var CBool job_ticket := shunt (options option "escp2_job_t
  heads := options option "escp2_heads" Int heads
  jets := options option "escp2_jets" Int jets
  dot_size := options option "escp2_dot_size" Int dot_size
  space_x := options option "escp2_space_x" Int space_x
  space_y := options option "escp2_space_y" Int space_y
  bpc := options option "escp2_bpc" Int (shunt old 1 2)
  dot_levels := options option "escp2_dot_levels" Int (shunt
  var CBool roll := options option "roll"
  if not ((options (options option_position "margin" 0) opti
    margin_right := 0 ; margin_bottom := 0
    if not ((options (options option_position "offset" 0) op
      margin_left := 0 ; margin_top := 0
  if not ((options (options option_position "page" options:l
    if roll or page_x=undefined or page_y=undefined
      page_x := margin_left+(abs h:x1-h:x0)+margin_right
      page_y := margin_top+(abs h:y1-h:y0)+margin_bottom
  margin_right := page_x-(abs h:x1-h:x0)-margin_left
  margin_bottom := page_y-(abs h:y1-h:y0)-margin_top
  if job_ticket and not (options option "esp2_no_ejl")
    s writechars "[0][0][0]"
    s writechars escape+character:1+"@EJL 1284.4[lf]@EJL    
    s writechars escape+"@"
  s writechars escape+"@"
  if job_ticket
    s writechars (escp2 "R" "[0]REMOTE1")
    if (options option "escp2_paper")
      s writechars (remote "SN" "[0][0]"+character:(options 
    if (options option "escp2_load")
      s writechars (remote "SN" "[0]"+character:2+character:
    if (command option "duplex") and ( (options option "fron
      s writechars (remote "SN" "[0]"+character:7+character:
    if (command option "zero_margin")
      s writechars (remote "FP" "[0]"+character:B0h+characte
    if (command option "ac_cutter")
      s writechars (remote "AC" "[0]"+character:(shunt (opti
    if (command option "co_cutter") and (options option "cut
      var Int cutter_unit := shunt page_unit=360 0 page_unit
      if cutter_unit=defined
        if (options option "double_cut")
          s writechars (remote "CO" "[0][0]"+character:1+cha
        s writechars (remote "CO" "[0][0]"+character:0+chara
    if (options option "escp2_dry")
      s writechars (remote "DR" "[0][0]"+num2:(cast (options
    if (options option "escp2_pause")
      s writechars (remote "DR" "[0]"+character:1+num2:(cast
    if (options option "escp2_ink")
      s writechars (remote "IK" "[0]"+character:(options opt
    if (command option "roll")
      s writechars (remote "EX"  "[0][0][0][0]"+character:5+
    if (options option "escp2_thickness")
      s writechars (remote "PH" "[0]"+character:(cast (optio
    s writechars escape+"[0][0][0]"
  s writechars (escp2 "G" character:1) # graphic mode
  if not old
    s writechars (escp2 "U" (num1 base_unit\page_unit)+(num1
  else
    s writechars (escp2 "U" (num1 3600\dpi_y))
  s writechars (escp2 "K" "[0]"+character:2) # color mode
  s writechars (escp2 "i" character:(options option "escp2_m
  s writechars escape+"U"+character:(shunt (options option "
  s writechars (escp2 "e" "[0]"+character:dot_size) # set do
  if not old
    s writechars (escp2 "D" num2:14400+(num1 14400\dpi_y*spa
  if not (options option "escp2_no_page")
    s writechars (escp2 "C" (num2_or_4 coord4 (cast page_y*p
    # desable vertical margin in order to allow vertical uni
    s writechars (escp2 "c" (num2_or_4 coord4 0)+(num2_or_4 
  if (options option "escp2_sheet") and ((options (options o
    s writechars (escp2 "S" num4:(cast sheet_x*page_unit/25.
  f stream :> s
  f:input_line size := h size_y
  for (var Int y) 0 f:input_line:size-1
    f:input_line y := null
  f dim := h:gamut dimension
  f size_x := h size_x
  f size_y := h size_y
  f input_y := 0 ; f input_line_size := h line_size
  f dpi_x := dpi_x
  f dpi_y := dpi_y
  f space_x := space_x
  f space_y := space_y
  f heads := heads
  f jets := jets
  f dot_size := dot_size
  f dot_levels := dot_levels
  f bpc := bpc
  f:shift size := heads_count
  var Int sm := 0
  for (var Int i) 0 heads_count-1
    if i<shift:size
      f:shift i := shift:i*dpi_y\dpi_shift
      sm := max sm f:shift:i
    else
      f:shift i := 0
  f delta := jets*space_y+sm
  f old := old
  f coord4 := coord4
  f job_ticket := job_ticket
  f command := command ; f options := options
  f advanced := options option "escp2_advanced"
  f:pass size := h:size_y+2*f:delta
  for (var Int y) 0 f:pass:size-1
    f:pass y := 0
  f output_line_size := (h:size_x\space_x*bpc+7)\8
  f output_lines := memory_allocate f:output_line_size*jets 
  f output_y := -(f delta)
  f left := cast margin_left*dpi_x/25.4 Int
  if top_enhancement
    f top := cast margin_top*dpi_y/25.4 Int
  else
    f top := max (cast margin_top*dpi_y/25.4 Int) f:delta
  f buffer := memory_allocate 2*f:output_line_size*jets+4 ad
  for (var Int i) 0 heads_count-1
    if (heads .and. 2^i)<>0
      var Pointer:Escp2Channel ch :> f:head i
      var Float middle := options option "escp2_middle"+(str
      var Float density := options option "escp2_density"+(s
      if i<4
        if (ch:dither load "file:/pliant_data/pliant/graphic
          var Int m1 := options option "escp2_matrix_mini" I
          var Int m2 := options option "escp2_matrix_maxi" I
          part shake "select dithering pattern size for chan
            part shake_x
              var Int sx := m1+(random m2-m1+1)
              if not is_prime:sx
                restart shake_x
            part shake_y
              var Int sy := m1+(random m2-m1+1)
              if not is_prime:sy
                restart shake_y
            for (var Int j) 0 i-1
              if f:head:j:dither:size_x=sx or f:head:j:dithe
                restart shake
          part matrix "compute "+string:sx+" x "+string:sy+"
            ch dither := random_matrix sx sy 64 16 (shunt dp
          ch:dither save "file:/pliant_data/pliant/graphic/d
      var CBool light_available := (heads .and. 2^(i%4+4))<>
      var Int nb := f:head:(i%4):dither:size_x*f:head:(i%4):
      if not f:advanced
        var Float light_gain := options option "escp2_light_
        var Float light_removal_start := options option "esc
        var Float light_removal_power := options option "esc
        var Float big_start := options option "escp2_big_sta
        var Float big_power := options option "escp2_big_pow
        var CBool oops := false
        for (var Int j) 0 255
          var Pointer:Escp2Lut ll :> ch:lut j
          var Float d := j/255
          d := (exposure d middle)*density
          ll light_threshold := shunt not light_available 0 
          ll light_removal := shunt d<=light_removal_start 0
          ll small := cast d*nb Int
          ll big_threshold := shunt dot_levels=1 0 d<=big_st
          if ll:light_threshold>0 and ll:light_removal<ll:bi
            oops := true
        if oops
          console "Light/big point selection conflict in ESC
      else
        var Str bend := string (options option "escp2_bend"+
        var Str ident := shunt (options option "escp2_dot"+(
        var Str opt := shunt (options option ident) options 
        var Array:Int dot ; var Array:Float dot_density ; va
        dot size := 0 ; dot_density size := 0 ; dot_bend siz
        dot += 0 ; dot_density += 0 ; dot_bend += 0
        var Int j := 0
        while (opt option_position ident j -1)>=0
          if not ((opt (opt option_position ident j opt:len)
            return (failure "Icorrect '"+ident+"' parameter"
          if light_available or dot0>=0
            dot += shunt i<4 and dot0>0 dot0 i>=4 and dot0<0
          j += 1
        for (var Int j) 0 255
          var Float d := j/255
          d := (exposure d middle)*density
          var Int k := 0
          while k+2<dot_density:size and d>=(dot_density k+1
            k += 1
          var Pointer:Escp2Level l :> ch:level j
          l dot0 := dot k
          l dot1 := dot k+1
          l remain := cast (exposure (d-dot_density:k)/(dot_
  status := success



  eif model="Epson 7600" or model="Epson 9600" or model="Eps
    heads := shunt model="Epson 10600" 03Fh 0BFh
    jets := 1
    dot_size := 10h
    space_x := 1
    space_y := 1
    command := "coord4 roll ac_cutter"
  else
    return (failure "'"+model+"' is not a valid printer mode
  command := options option "escp2_command" Str command
  var CBool old := command option "old"
  var CBool coord4 := command option "coord4"
  var CBool job_ticket := shunt (options option "escp2_job_t
  heads := options option "escp2_heads" Int heads
  jets := options option "escp2_jets" Int jets
  dot_size := options option "escp2_dot_size" Int dot_size
  space_x := options option "escp2_space_x" Int space_x
  space_y := options option "escp2_space_y" Int space_y
  bpc := options option "escp2_bpc" Int (shunt old 1 2)
  dot_levels := options option "escp2_dot_levels" Int (shunt
  var CBool roll := options option "roll"
  if not ((options (options option_position "margin" 0) opti
    margin_right := 0 ; margin_bottom := 0
    if not ((options (options option_position "offset" 0) op
      margin_left := 0 ; margin_top := 0
  if not ((options (options option_position "page" options:l
    if roll or page_x=undefined or page_y=undefined
      page_x := margin_left+(abs h:x1-h:x0)+margin_right
      page_y := margin_top+(abs h:y1-h:y0)+margin_bottom
  margin_right := page_x-(abs h:x1-h:x0)-margin_left
  margin_bottom := page_y-(abs h:y1-h:y0)-margin_top
  if job_ticket and not (options option "esp2_no_ejl")
    s writechars "[0][0][0]"
    s writechars escape+character:1+"@EJL 1284.4[lf]@EJL    
    s writechars escape+"@"
  s writechars escape+"@"
  if job_ticket
    s writechars (escp2 "R" "[0]REMOTE1")
    if (options option "escp2_paper")
      s writechars (remote "SN" "[0][0]"+character:(options 
    if (options option "escp2_load")
      s writechars (remote "SN" "[0]"+character:2+character:
    if (command option "duplex") and ( (options option "fron
      s writechars (remote "SN" "[0]"+character:7+character:
    if (command option "zero_margin")
      s writechars (remote "FP" "[0]"+character:B0h+characte
    if (command option "ac_cutter")
      s writechars (remote "AC" "[0]"+character:(shunt (opti
    if (command option "co_cutter") and (options option "cut
      var Int cutter_unit := shunt page_unit=360 0 page_unit
      if cutter_unit=defined
        if (options option "double_cut")
          s writechars (remote "CO" "[0][0]"+character:1+cha
        s writechars (remote "CO" "[0][0]"+character:0+chara
    if (options option "escp2_dry")
      s writechars (remote "DR" "[0][0]"+num2:(cast (options
    if (options option "escp2_pause")
      s writechars (remote "DR" "[0]"+character:1+num2:(cast
    if (options option "escp2_ink")
      s writechars (remote "IK" "[0]"+character:(options opt
    if (command option "roll")
      s writechars (remote "EX"  "[0][0][0][0]"+character:5+
    if (options option "escp2_thickness")
      s writechars (remote "PH" "[0]"+character:(cast (optio
    s writechars escape+"[0][0][0]"
  s writechars (escp2 "G" character:1) # graphic mode
  if not old
    s writechars (escp2 "U" (num1 base_unit\page_unit)+(num1
  else
    s writechars (escp2 "U" (num1 3600\dpi_y))
  s writechars (escp2 "K" "[0]"+character:2) # color mode
  s writechars (escp2 "i" character:(options option "escp2_m
  s writechars escape+"U"+character:(shunt (options option "
  s writechars (escp2 "e" "[0]"+character:dot_size) # set do
  if not old
    s writechars (escp2 "D" num2:14400+(num1 14400\dpi_y*spa
  if not (options option "escp2_no_page")
    s writechars (escp2 "C" (num2_or_4 coord4 (cast page_y*p
    # desable vertical margin in order to allow vertical uni
    s writechars (escp2 "c" (num2_or_4 coord4 0)+(num2_or_4 
  if (options option "escp2_sheet") and ((options (options o
    s writechars (escp2 "S" num4:(cast sheet_x*page_unit/25.
  f stream :> s
  f:input_line size := h size_y
  for (var Int y) 0 f:input_line:size-1
    f:input_line y := null
  f dim := h:gamut dimension
  f size_x := h size_x
  f size_y := h size_y
  f input_y := 0 ; f input_line_size := h line_size
  f dpi_x := dpi_x
  f dpi_y := dpi_y
  f space_x := space_x
  f space_y := space_y
  f heads := heads
  f jets := jets
  f dot_size := dot_size
  f dot_levels := dot_levels
  f bpc := bpc
  f:shift size := heads_count
  var Int sm := 0
  for (var Int i) 0 heads_count-1
    if i<shift:size
      f:shift i := shift:i*dpi_y\dpi_shift
      sm := max sm f:shift:i
    else
      f:shift i := 0
  f delta := jets*space_y+sm
  f old := old
  f coord4 := coord4
  f job_ticket := job_ticket
  f command := command ; f options := options
  f advanced := options option "escp2_advanced"
  f:pass size := h:size_y+2*f:delta
  for (var Int y) 0 f:pass:size-1
    f:pass y := 0
  f output_line_size := (h:size_x\space_x*bpc+7)\8
  f output_lines := memory_allocate f:output_line_size*jets 
  f output_y := -(f delta)
  f left := cast margin_left*dpi_x/25.4 Int
  if top_enhancement
    f top := cast margin_top*dpi_y/25.4 Int
  else
    f top := max (cast margin_top*dpi_y/25.4 Int) f:delta
  f buffer := memory_allocate 2*f:output_line_size*jets+4 ad
  for (var Int i) 0 heads_count-1
    if (heads .and. 2^i)<>0
      var Pointer:Escp2Channel ch :> f:head i
      var Float middle := options option "escp2_middle"+(str
      var Float density := options option "escp2_density"+(s
      if i<4
        if (ch:dither load "file:/pliant_data/pliant/graphic
          var Int m1 := options option "escp2_matrix_mini" I
          var Int m2 := options option "escp2_matrix_maxi" I
          part shake "select dithering pattern size for chan
            part shake_x
              var Int sx := m1+(random m2-m1+1)
              if not is_prime:sx
                restart shake_x
            part shake_y
              var Int sy := m1+(random m2-m1+1)
              if not is_prime:sy
                restart shake_y
            for (var Int j) 0 i-1
              if f:head:j:dither:size_x=sx or f:head:j:dithe
                restart shake
          part matrix "compute "+string:sx+" x "+string:sy+"
            ch dither := random_matrix sx sy 64 16 (shunt dp
          ch:dither save "file:/pliant_data/pliant/graphic/d
      var CBool light_available := (heads .and. 2^(i%4+4))<>
      var Int nb := f:head:(i%4):dither:size_x*f:head:(i%4):
      if not f:advanced
        var Float light_gain := options option "escp2_light_
        var Float light_removal_start := options option "esc
        var Float light_removal_power := options option "esc
        var Float big_start := options option "escp2_big_sta
        var Float big_power := options option "escp2_big_pow
        var CBool oops := false
        for (var Int j) 0 255
          var Pointer:Escp2Lut ll :> ch:lut j
          var Float d := j/255
          d := (exposure d middle)*density
          ll light_threshold := shunt not light_available 0 
          ll light_removal := shunt d<=light_removal_start 0
          ll small := cast d*nb Int
          ll big_threshold := shunt dot_levels=1 0 d<=big_st
          if ll:light_threshold>0 and ll:light_removal<ll:bi
            oops := true
        if oops
          console "Light/big point selection conflict in ESC
      else
        var Str bend := string (options option "escp2_bend"+
        var Str ident := shunt (options option "escp2_dot"+(
        var Str opt := shunt (options option ident) options 
        var Array:Int dot ; var Array:Float dot_density ; va
        dot size := 0 ; dot_density size := 0 ; dot_bend siz
        dot += 0 ; dot_density += 0 ; dot_bend += 0
        var Int j := 0
        while (opt option_position ident j -1)>=0
          if not ((opt (opt option_position ident j opt:len)
            return (failure "Icorrect '"+ident+"' parameter"
          if light_available or dot0>=0
            dot += shunt i<4 and dot0>0 dot0 i>=4 and dot0<0
          j += 1
        for (var Int j) 0 255
          var Float d := j/255
          d := (exposure d middle)*density
          var Int k := 0
          while k+2<dot_density:size and d>=(dot_density k+1
            k += 1
          var Pointer:Escp2Level l :> ch:level j
          l dot0 := dot k
          l dot1 := dot k+1
          l remain := cast (exposure (d-dot_density:k)/(dot_
  status := success



image_record_filters ".escp2" Void ImageWriteFilterEscp2
image_record_filters ".escp2" Void false ImageWriteFilterEscp2 false
export escp2_generator
export escp2_generator