| |
| /pliant/graphic/filter/escp2.pli |
| |
| 1 |
# Copyright Hubert Tonneau hubert.tonneau@pliant.cx | |
| 2 |
# | |
| 3 |
# Writing this driver was possible only thanks to the great work done by | |
| 4 |
# Robert L Krawitz to gather and document detailed informations about | |
| 5 |
# Epson inkjet printers. | |
| 6 |
# | |
| 7 |
# Things have now changed since Epson is publishing new inkjets printers | |
| 8 |
# programming documentation | |
| 9 |
| |
| 10 |
| |
| 11 |
module "/pliant/language/compiler.pli" | |
| 12 |
module "/pliant/language/context.pli" | |
| 13 |
module "/pliant/language/stream.pli" | |
| 14 |
module "/pliant/math/functions.pli" | |
| 15 |
module "prototype.pli" | |
| 16 |
module "/pliant/graphic/color/gamut.pli" | |
| 17 |
module "/pliant/util/encoding/packbits.pli" | |
| 18 |
module "/pliant/graphic/image/pixmap.pli" | |
| 19 |
module "/pliant/graphic/color/adjust.pli" | |
| 20 |
module "/pliant/graphic/color/spectrum.pli" # defines 'exposure' function | |
| 21 |
module "/pliant/graphic/misc/dither.pli" | |
| 22 |
| |
| 23 |
constant packbits true | |
| 24 |
constant heads_count 12 | |
| 25 |
constant top_enhancement true | |
| 26 |
constant verbose false | |
| 27 |
| |
| 28 |
gvar Link:Function escp2_generator | |
| 29 |
| |
| 30 |
| |
| 31 |
| |
| 32 |
| |
| 33 |
# driving the printer | |
| 34 |
| |
| 35 |
| |
| 36 |
function generator_prototype x y head level f -> dot | |
| 37 |
arg Int x y head level ; arg Function f ; arg Int dot | |
| 38 |
indirect | |
| 39 |
| |
| 40 |
type Escp2Level | |
| 41 |
field uInt16 dot0 dot1 | |
| 42 |
field uInt32 remain | |
| 43 |
| |
| 44 |
type Escp2Lut | |
| 45 |
field Int light_threshold | |
| 46 |
field Int light_removal | |
| 47 |
field Int small | |
| 48 |
field Int big_threshold | |
| 49 |
| |
| 50 |
type Escp2Channel | |
| 51 |
field (Array Escp2Level 256) level | |
| 52 |
field (Array Escp2Lut 256) lut | |
| 53 |
field DitherMatrix dither | |
| 54 |
| |
| 55 |
type ImageWriteFilterEscp2 | |
| 56 |
field Pointer:Stream stream | |
| 57 |
field Array:Address input_line | |
| 58 |
field Int dim | |
| 59 |
field Int size_x size_y | |
| 60 |
field Int input_y input_line_size | |
| 61 |
field Int dpi_x dpi_y space_x space_y heads jets dot_size bpc hq_dpi dot_levels big_dot | |
| 62 |
field Array:Int shift | |
| 63 |
field Array:Int pass ; field Int delta | |
| 64 |
field CBool old coord4 job_ticket | |
| 65 |
field Str command options | |
| 66 |
field CBool advanced | |
| 67 |
field Address output_lines ; field Int output_line_size | |
| 68 |
field Int output_y | |
| 69 |
field Int left top | |
| 70 |
field Address buffer | |
| 71 |
field (Array Escp2Channel heads_count) head | |
| 72 |
if top_enhancement | |
| 73 |
field (Array List:Str) top_lines | |
| 74 |
| |
| 75 |
ImageWriteFilter maybe ImageWriteFilterEscp2 | |
| 76 |
| |
| 77 |
| |
| 78 |
constant escape character:27 | |
| 79 |
| |
| 80 |
function num1 i -> s | |
| 81 |
arg Int i ; arg Str s | |
| 82 |
s := "1" ; s:characters map uInt8 := i | |
| 83 |
| |
| 84 |
function num2 i -> s | |
| 85 |
arg Int i ; arg Str s | |
| 86 |
s := "12" ; s:characters map uInt16_li := i | |
| 87 |
| |
| 88 |
function num4 i -> s | |
| 89 |
arg Int i ; arg Str s | |
| 90 |
s := "1234" ; s:characters map uInt32_li := i | |
| 91 |
| |
| 92 |
function num2_or_4 coord4 i -> s | |
| 93 |
arg CBool coord4 ; arg Int i ; arg Str s | |
| 94 |
if coord4 | |
| 95 |
s := num4 i | |
| 96 |
else | |
| 97 |
s := num2 i | |
| 98 |
| |
| 99 |
function escp2 command parameters -> s | |
| 100 |
arg Str command parameters s | |
| 101 |
s := escape+"("+command+(num2 parameters:len)+parameters | |
| 102 |
| |
| 103 |
function remote command parameters -> s | |
| 104 |
arg Str command parameters s | |
| 105 |
s := command+(num2 parameters:len)+parameters | |
| 106 |
| |
| 107 |
method f open s options h -> status | |
| 108 |
arg_rw ImageWriteFilterEscp2 f ; arg_rw Stream s ; arg Str options ; arg ImagePrototype h ; arg ExtendedStatus status | |
| 109 |
var Int dpi_x dpi_y base_unit page_unit | |
| 110 |
var Int heads jets dot_size bpc dot_levels space_x space_y | |
| 111 |
var Int dpi_shift ; var Array:Int shift | |
| 112 |
var Float page_x := undefined ; var Float page_y := undefined | |
| 113 |
var Str command | |
| 114 |
dpi_x := options option "escp2_dpi_x" Int (cast h:size_x/(abs h:x1-h:x0)*25.4 Int) | |
| 115 |
dpi_y := options option "escp2_dpi_y" Int (cast h:size_y/(abs h:y1-h:y0)*25.4 Int) | |
| 116 |
if (dpi_x%360<>0 or dpi_y%360<>0) and not (options option "escp2_force_resolution") | |
| 117 |
return (failure "Incorrect resolution "+string:dpi_x+" x "+string:dpi_y+" dpi") | |
| 118 |
base_unit := options option "escp2_base_unit" Int (max (max dpi_x dpi_y) 1440) | |
| 119 |
page_unit := options option "escp2_page_unit" Int (max (max dpi_x dpi_y) 720) | |
| 120 |
var Str model := options option "model" Str | |
| 121 |
if model="" | |
| 122 |
return failure:"You must specify the printer model" | |
| 123 |
if model="Epson C80" or model="Epson C82" | |
| 124 |
heads := 0Fh | |
| 125 |
jets := shunt h:gamut:dimension=1 180 60 | |
| 126 |
dot_size := 12h | |
| 127 |
if h:gamut:dimension<>1 | |
| 128 |
dpi_shift := 180 ; shift += 120 ; shift += 60 ; shift += 0 ; shift += 120 | |
| 129 |
space_x := dpi_x\360 | |
| 130 |
space_y := dpi_y\180 | |
| 131 |
page_x := 210 | |
| 132 |
page_y := 297 | |
| 133 |
command := "" | |
| 134 |
eif model="Epson 750" | |
| 135 |
heads := 30Fh | |
| 136 |
jets := 48 | |
| 137 |
dot_size := 10h | |
| 138 |
space_x := dpi_x\360 | |
| 139 |
space_y := dpi_y\120 | |
| 140 |
page_x := 210 | |
| 141 |
page_y := 297 | |
| 142 |
command := "" | |
| 143 |
eif model="Epson 1280" or model="Epson 1290" | |
| 144 |
heads := 30Fh | |
| 145 |
jets := 48 | |
| 146 |
dot_size := 10h | |
| 147 |
space_x := dpi_x\360 | |
| 148 |
space_y := dpi_y\120 | |
| 149 |
page_x := 13*25.4 | |
| 150 |
page_y := 19*25.4 | |
| 151 |
command := "coord4 zero_margin roll" | |
| 152 |
eif model="Epson 2100" or model="Epson 2200" | |
| 153 |
heads := 0B0Fh | |
| 154 |
jets := 96 | |
| 155 |
dot_size := 10h | |
| 156 |
if h:gamut:dimension<>1 | |
| 157 |
dpi_shift := 360 ; shift += 0 ; shift += 0 ; shift += 0 ; shift += 0 ; shift += 0 ; shift += 0 ; shift += 0 ; shift += 0 ; shift += 1 ; shift += 1 ; shift += 0 ; shift += 1 | |
| 158 |
space_x := dpi_x\360 | |
| 159 |
space_y := dpi_y\180 | |
| 160 |
page_x := 13*25.4 | |
| 161 |
page_y := 19*25.4 | |
| 162 |
command := "coord4 zero_margin roll co_cutter" | |
| 163 |
eif model="Epson 3000" | |
| 164 |
heads := 0Fh | |
| 165 |
jets := shunt h:gamut:dimension=1 128 64 | |
| 166 |
dot_size := 1 | |
| 167 |
space_x := dpi_x\360 | |
| 168 |
space_y := dpi_y\180 | |
| 169 |
page_x := 17*25.4 | |
| 170 |
page_y := 44*25.4 | |
| 171 |
command := "old" | |
| 172 |
eif model="Epson 4000" | |
| 173 |
heads := 0B0Fh | |
| 174 |
jets := 1 | |
| 175 |
dot_size := 12h | |
| 176 |
space_x := 1 | |
| 177 |
space_y := 1 | |
| 178 |
page_x := 17*25.4 | |
| 179 |
page_y := 44*25.4 | |
| 180 |
command := "coord4 roll ac_cutter" | |
| 181 |
eif model="Epson 7600" or model="Epson 9600" or model="Epson 10600" | |
| 182 |
heads := shunt model="Epson 10600" 030Fh 0B0Fh | |
| 183 |
jets := 1 | |
| 184 |
dot_size := 10h | |
| 185 |
space_x := 1 | |
| 186 |
space_y := 1 | |
| 187 |
command := "coord4 roll ac_cutter" | |
| 188 |
eif model="Epson R800" | |
| 189 |
if h:gamut:dimension<>1 | |
| 190 |
dpi_shift := 360 ; shift += 0 ; shift += 1 ; shift += 0 ; shift += 0 ; shift += 1 ; shift += 0 | |
| 191 |
heads := 7Fh | |
| 192 |
jets := 180 | |
| 193 |
dot_size := 13h | |
| 194 |
space_x := dpi_x\720 | |
| 195 |
space_y := dpi_y\180 | |
| 196 |
page_x := 210 | |
| 197 |
page_y := 297 | |
| 198 |
command := "coord4 zero_margin roll co_cutter matte_black" | |
| 199 |
else | |
| 200 |
return (failure "'"+model+"' is not a valid printer model") | |
| 201 |
command := options option "escp2_command" Str command | |
| 202 |
var CBool old := command option "old" | |
| 203 |
var CBool coord4 := command option "coord4" | |
| 204 |
var CBool job_ticket := shunt (options option "escp2_job_ticket") true (options option "escp2_no_job_ticket") false not old | |
| 205 |
heads := options option "escp2_heads" Int heads | |
| 206 |
jets := options option "escp2_jets" Int jets | |
| 207 |
dot_size := options option "escp2_dot_size" Int dot_size | |
| 208 |
space_x := options option "escp2_space_x" Int space_x | |
| 209 |
space_y := options option "escp2_space_y" Int space_y | |
| 210 |
bpc := options option "escp2_bpc" Int (shunt old 1 2) | |
| 211 |
dot_levels := options option "escp2_dot_levels" Int (shunt dpi_x>=1440 or dpi_y>=1440 1 2^bpc-1) | |
| 212 |
var CBool roll := options option "roll" | |
| 213 |
if not ((options (options option_position "margin" 0) options:len) parse word:"margin" (var Float margin_left) (var Float margin_top) (var Float margin_right) (var Float margin_bottom) any) | |
| 214 |
margin_right := 0 ; margin_bottom := 0 | |
| 215 |
if not ((options (options option_position "offset" 0) options:len) parse word:"offset" (var Float margin_left) (var Float margin_top) any) | |
| 216 |
margin_left := 0 ; margin_top := 0 | |
| 217 |
if not ((options (options option_position "page" options:len) options:len) parse word:"page" (var Float page_x) (var Float page_y) any) | |
| 218 |
if roll or page_x=undefined or page_y=undefined | |
| 219 |
page_x := margin_left+(abs h:x1-h:x0)+margin_right | |
| 220 |
page_y := margin_top+(abs h:y1-h:y0)+margin_bottom | |
| 221 |
margin_right := page_x-(abs h:x1-h:x0)-margin_left | |
| 222 |
margin_bottom := page_y-(abs h:y1-h:y0)-margin_top | |
| 223 |
if job_ticket and not (options option "esp2_no_ejl") | |
| 224 |
s writechars "[0][0][0]" | |
| 225 |
s writechars escape+character:1+"@EJL 1284.4[lf]@EJL [lf]" | |
| 226 |
s writechars escape+"@" | |
| 227 |
s writechars escape+"@" | |
| 228 |
if job_ticket | |
| 229 |
s writechars (escp2 "R" "[0]REMOTE1") | |
| 230 |
if (options option "escp2_paper") | |
| 231 |
s writechars (remote "SN" "[0][0]"+character:(options option "escp2_paper" Int 0)) # paper 0=default, 1=plain, 3=glossy photo, 5=plain (fast load), 6=heavyweight matte, 7=coated, 8=photo | |
| 232 |
if (options option "escp2_load") | |
| 233 |
s writechars (remote "SN" "[0]"+character:2+character:(options option "escp2_load" Int 0)) # 0=normal, 1=fast, 2=slow | |
| 234 |
if (command option "duplex") and ( (options option "front") or (options option "back")) | |
| 235 |
s writechars (remote "SN" "[0]"+character:7+character:(shunt (options option "front") 1 2)) | |
| 236 |
if (command option "zero_margin") | |
| 237 |
s writechars (remote "FP" "[0]"+character:B0h+character:0FFh) # zero margin | |
| 238 |
if (command option "ac_cutter") | |
| 239 |
s writechars (remote "AC" "[0]"+character:(shunt (options option "cutter") 1 0)) # cutter | |
| 240 |
if (command option "co_cutter") and (options option "cutter") | |
| 241 |
var Int cutter_unit := shunt page_unit=360 0 page_unit=720 1 page_unit=1440 2 (cast undefined Int) | |
| 242 |
if cutter_unit=defined | |
| 243 |
if (options option "double_cut") | |
| 244 |
s writechars (remote "CO" "[0][0]"+character:1+character:cutter_unit+"[0][0][0][0]") | |
| 245 |
s writechars (remote "CO" "[0][0]"+character:0+character:cutter_unit+num4:(cast page_y*page_unit/25.4 Int)) | |
| 246 |
if (options option "escp2_dry") | |
| 247 |
s writechars (remote "DR" "[0][0]"+num2:(cast (options option "escp_dry" Float 0)*1000 Int)) # dry time between scan lines | |
| 248 |
if (options option "escp2_pause") | |
| 249 |
s writechars (remote "DR" "[0]"+character:1+num2:(cast (options option "escp_dry" Float 0) Int)) # dry time between page | |
| 250 |
if (options option "escp2_ink") | |
| 251 |
s writechars (remote "IK" "[0]"+character:(options option "escp2_ink" Int 0)) | |
| 252 |
if (command option "roll") | |
| 253 |
s writechars (remote "EX" "[0][0][0][0]"+character:5+character:(shunt roll 1 0)) # roll | |
| 254 |
if (options option "escp2_thickness") | |
| 255 |
s writechars (remote "PH" "[0]"+character:(cast (options option "escp2_thickness" Float 0)*10 Int)) | |
| 256 |
s writechars escape+"[0][0][0]" | |
| 257 |
s writechars (escp2 "G" character:1) # graphic mode | |
| 258 |
if not old | |
| 259 |
s writechars (escp2 "U" (num1 base_unit\page_unit)+(num1 base_unit\dpi_y)+(num1 base_unit\dpi_x)+num2:base_unit) | |
| 260 |
else | |
| 261 |
s writechars (escp2 "U" (num1 3600\dpi_y)) | |
| 262 |
s writechars (escp2 "K" "[0]"+character:2) # color mode | |
| 263 |
s writechars (escp2 "i" character:(options option "escp2_microweave" Int 0)+(shunt (options option "escp2_microweave2") character:(options option "escp2_microweave2" Int 0)+character:(options option "escp2_microweave3" Int 0) "")) # microweave | |
| 264 |
s writechars escape+"U"+character:(shunt (options option "unidirectional") 1 0) # unidirectional | |
| 265 |
s writechars (escp2 "e" "[0]"+character:dot_size) # set dots size | |
| 266 |
if not old | |
| 267 |
s writechars (escp2 "D" num2:14400+(num1 14400\dpi_y*space_y)+(num1 14400\dpi_x*space_x)) # dots spacing | |
| 268 |
if not (options option "escp2_no_page") | |
| 269 |
s writechars (escp2 "C" (num2_or_4 coord4 (cast page_y*page_unit/25.4 Int))) # page length | |
| 270 |
# desable vertical margin in order to allow vertical units to start right at the top of the page | |
| 271 |
s writechars (escp2 "c" (num2_or_4 coord4 0)+(num2_or_4 coord4 (cast page_y*page_unit/25.4 Int))) # vertical margin | |
| 272 |
if (options option "escp2_sheet") and ((options (options option_position "sheet" options:len) options:len) parse word:"sheet" (var Float sheet_x) (var Float sheet_y) any) | |
| 273 |
s writechars (escp2 "S" num4:(cast sheet_x*page_unit/25.4 Int)+num4:(cast sheet_y*page_unit/25.4 Int)) # sheet size | |
| 274 |
f stream :> s | |
| 275 |
f:input_line size := h size_y | |
| 276 |
for (var Int y) 0 f:input_line:size-1 | |
| 277 |
f:input_line y := null | |
| 278 |
f dim := h:gamut dimension | |
| 279 |
f size_x := h size_x | |
| 280 |
f size_y := h size_y | |
| 281 |
f input_y := 0 ; f input_line_size := h line_size | |
| 282 |
f dpi_x := dpi_x | |
| 283 |
f dpi_y := dpi_y | |
| 284 |
f space_x := space_x | |
| 285 |
f space_y := space_y | |
| 286 |
f heads := heads | |
| 287 |
f jets := jets | |
| 288 |
f dot_size := dot_size | |
| 289 |
f dot_levels := dot_levels | |
| 290 |
f bpc := bpc | |
| 291 |
f:shift size := heads_count | |
| 292 |
var Int sm := 0 | |
| 293 |
for (var Int i) 0 heads_count-1 | |
| 294 |
if i<shift:size | |
| 295 |
f:shift i := shift:i*dpi_y\dpi_shift | |
| 296 |
sm := max sm f:shift:i | |
| 297 |
else | |
| 298 |
f:shift i := 0 | |
| 299 |
f delta := jets*space_y+sm | |
| 300 |
f old := old | |
| 301 |
f coord4 := coord4 | |
| 302 |
f job_ticket := job_ticket | |
| 303 |
f command := command ; f options := options | |
| 304 |
f advanced := options option "escp2_advanced" | |
| 305 |
f:pass size := h:size_y+2*f:delta | |
| 306 |
for (var Int y) 0 f:pass:size-1 | |
| 307 |
f:pass y := 0 | |
| 308 |
f output_line_size := (h:size_x\space_x*bpc+7)\8 | |
| 309 |
f output_lines := memory_allocate f:output_line_size*jets addressof:f | |
| 310 |
f output_y := -(f delta) | |
| 311 |
f left := cast margin_left*dpi_x/25.4 Int | |
| 312 |
if top_enhancement | |
| 313 |
f top := cast margin_top*dpi_y/25.4 Int | |
| 314 |
else | |
| 315 |
f top := max (cast margin_top*dpi_y/25.4 Int) f:delta | |
| 316 |
f buffer := memory_allocate 2*f:output_line_size*jets+4 addressof:f | |
| 317 |
for (var Int i) 0 heads_count-1 | |
| 318 |
if (heads .and. 2^i)<>0 | |
| 319 |
var Pointer:Escp2Channel ch :> f:head i | |
| 320 |
if i<8 | |
| 321 |
ch dither := dither_matrix i "dpi_x "+string:dpi_x+" dpi_y "+string:dpi_y | |
| 322 |
var CBool light_available := (heads .and. 2^(i%8+8))<>0 | |
| 323 |
var Int nb := f:head:(i%8):dither:size_x*f:head:(i%8):dither:size_y | |
| 324 |
if not f:advanced | |
| 325 |
var Float light_gain := options option "escp2_light_gain"+(string i%8) Float (options option "escp2_light_gain" Float 0.25) | |
| 326 |
var Float light_removal_start := options option "escp2_light_removal_start"+(string i%8) Float (options option "escp2_light_removal_start" Float 0.0625) | |
| 327 |
var Float light_removal_power := options option "escp2_light_removal_power"+(string i%8) Float (options option "escp2_light_removal_power" Float 1.25) | |
| 328 |
var Float big_start := options option "escp2_big_start"+(string i%8) Float (options option "escp2_big_start" Float 0.5) | |
| 329 |
var Float big_power := options option "escp2_big_power"+(string i%8) Float (options option "escp2_big_power" Float 2) | |
| 330 |
var CBool oops := false | |
| 331 |
for (var Int j) 0 255 | |
| 332 |
var Pointer:Escp2Lut ll :> ch:lut j | |
| 333 |
var Float d := j/255 | |
| 334 |
d := dot_adjust d "header [dq]escp2_head"+(string i%8)+"_[dq] header2 [dq]escp2_[dq] "+options | |
| 335 |
ll light_threshold := shunt not light_available 0 (cast (exposure d light_gain)*nb Int) | |
| 336 |
ll light_removal := shunt d<=light_removal_start 0 (cast ((d-light_removal_start)/(1-light_removal_start))^light_removal_power*nb Int) | |
| 337 |
ll small := cast d*nb Int | |
| 338 |
ll big_threshold := shunt dot_levels=1 0 d<=big_start 0 (cast ((d-big_start)/(1-big_start))^big_power*nb Int) | |
| 339 |
if ll:light_threshold>0 and ll:light_removal<ll:big_threshold | |
| 340 |
oops := true | |
| 341 |
if oops | |
| 342 |
console "Light/big point selection conflict in ESCP2 driver" eol | |
| 343 |
else | |
| 344 |
var Str bend := string (options option "escp2_bend"+(string i%8) Float (options option "escp2_bend" Float -0.1)) | |
| 345 |
var Str ident := shunt (options option "escp2_dot"+(string i%8)) "escp2_dot"+(string i%8) "escp2_dot" | |
| 346 |
var Str opt := shunt (options option ident) options bpc=1 "escp2_dot -1 0.5 "+bend+" escp2_dot 1 1 "+bend "escp2_dot -1 0.333 "+bend+" escp2_dot 1 0.667 "+bend+" escp2_dot 3 1 "+bend | |
| 347 |
var Array:Int dot ; var Array:Float dot_density ; var Array:Float dot_bend | |
| 348 |
dot size := 0 ; dot_density size := 0 ; dot_bend size := 0 | |
| 349 |
dot += 0 ; dot_density += 0 ; dot_bend += 0 | |
| 350 |
var Int j := 0 | |
| 351 |
while (opt option_position ident j -1)>=0 | |
| 352 |
if not ((opt (opt option_position ident j opt:len) opt:len) parse word:ident (var Int dot0) (var Float density0) (var Float bend0) any) | |
| 353 |
return (failure "Icorrect '"+ident+"' parameter") | |
| 354 |
if light_available or dot0>=0 | |
| 355 |
dot += shunt i<8 and dot0>0 dot0 i>=8 and dot0<0 -dot0 0 ; dot_density += density0 ; dot_bend += bend0 | |
| 356 |
j += 1 | |
| 357 |
for (var Int j) 0 255 | |
| 358 |
var Float d := j/255 | |
| 359 |
d := dot_adjust d "header [dq]escp2_head"+(string i%8)+"_[dq] header2 [dq]escp2_[dq] "+options | |
| 360 |
var Int k := 0 | |
| 361 |
while k+2<dot_density:size and d>=(dot_density k+1) | |
| 362 |
k += 1 | |
| 363 |
var Pointer:Escp2Level l :> ch:level j | |
| 364 |
l dot0 := dot k | |
| 365 |
l dot1 := dot k+1 | |
| 366 |
l remain := cast (exposure (d-dot_density:k)/(dot_density:(k+1)-dot_density:k) dot_bend:(k+1))*nb Int | |
| 367 |
status := success | |
| 368 |
| |
| 369 |
| |
| 370 |
method f writeline adr -> status | |
| 371 |
arg_rw ImageWriteFilterEscp2 f ; arg Address adr ; arg Status status | |
| 372 |
var Pointer:Stream s :> f stream | |
| 373 |
implicit f | |
| 374 |
| |
| 375 |
# record the newly provided line | |
| 376 |
input_line input_y := memory_allocate input_line_size addressof:f | |
| 377 |
memory_copy adr input_line:input_y input_line_size | |
| 378 |
input_y += 1 | |
| 379 |
| |
| 380 |
while output_y<size_y | |
| 381 |
if (pass output_y+delta)=2^space_x-1 | |
| 382 |
output_y -= 1 | |
| 383 |
while (pass output_y+delta)=2^space_x-1 | |
| 384 |
output_y += 1 | |
| 385 |
var Int p := 0 | |
| 386 |
while ((pass output_y+delta) .and. 2^p)<>0 | |
| 387 |
p += 1 | |
| 388 |
# 'first_line' and 'lines_count' is specifying the limits of the pass we are planing to send | |
| 389 |
for (var Int h) 0 heads_count-1 | |
| 390 |
for (var Int j) 0 jets-1 | |
| 391 |
var Int y := output_y+shift:h+j*space_y | |
| 392 |
if y>=0 and y<size_y and input_line:y=null | |
| 393 |
# one input line is missing: wait until the input data is received | |
| 394 |
return success | |
| 395 |
if verbose | |
| 396 |
console "escp2 line " output_y "/" size_y " [cr]" | |
| 397 |
# everything is fine for the pass: let's send it to the printer | |
| 398 |
var CBool vpos := true | |
| 399 |
for (var Int h) 0 heads_count-1 | |
| 400 |
var Int first_line := output_y+shift:h | |
| 401 |
var Int lines_count := min (size_y-first_line+space_y-1)\space_y jets | |
| 402 |
if (heads .and. 2^h)<>0 and lines_count>0 and (shunt dim=1 h%8=3 h%8<dim) | |
| 403 |
memory_clear f:output_lines output_line_size*lines_count ; var CBool some := false | |
| 404 |
for (var Int j) 0 lines_count-1 | |
| 405 |
var Int y := first_line+j*space_y | |
| 406 |
if y>=0 | |
| 407 |
var Address src := input_line:y translate uInt8 p*dim+(shunt dim=1 0 h%8) | |
| 408 |
var Int src_step := space_x*dim | |
| 409 |
if exists:escp2_generator | |
| 410 |
for (var Int x) p size_x-1 step space_x | |
| 411 |
var Int l := src map uInt8 | |
| 412 |
var Int d := generator_prototype x y h l escp2_generator | |
| 413 |
if d<>0 | |
| 414 |
output_lines map uInt8 j*output_line_size+(x\space_x)*bpc\8 += d*2^(8-bpc-(x\space_x)*bpc%8) | |
| 415 |
some := true | |
| 416 |
src := src translate uInt8 src_step | |
| 417 |
eif not f:advanced | |
| 418 |
var Address dest := output_lines translate uInt8 j*output_line_size+(p\space_x)*bpc\8 | |
| 419 |
var Int shift := 8-bpc-(p\space_x)*bpc%8 | |
| 420 |
var Int shift_step := bpc | |
| 421 |
var Pointer:(Array Escp2Lut 256) lut :> f:head:h:lut | |
| 422 |
var Pointer:DitherMatrix dither_matrix :> f:head:(h%8):dither | |
| 423 |
var Address dither := addressof (dither_matrix 0 y%dither_matrix:size_y) | |
| 424 |
var Int modulus := dither_matrix size_x | |
| 425 |
if false # unoptimised version | |
| 426 |
for (var Int x) p size_x-1 step space_x | |
| 427 |
var Int l := src map uInt8 | |
| 428 |
# handle pixel 'x' 'y' on head 'h' , which level is 'l' | |
| 429 |
if l<>0 | |
| 430 |
var Int d # 'd' will be the dot size | |
| 431 |
var Pointer:Escp2Lut ll :> lut l | |
| 432 |
var Int t := dither map Int x%modulus | |
| 433 |
var CBool light := ll:light_threshold>=t and not ll:light_removal>=t | |
| 434 |
var CBool big := ll:big_threshold>=t | |
| 435 |
var CBool small := ll:small>=t and not light and not big | |
| 436 |
if h<8 | |
| 437 |
d := shunt big 3 small 1 0 | |
| 438 |
else | |
| 439 |
d := shunt light 1 0 | |
| 440 |
if d<>0 | |
| 441 |
dest map uInt8 += d*2^shift | |
| 442 |
some := true | |
| 443 |
src := src translate uInt8 src_step | |
| 444 |
if shift>0 | |
| 445 |
shift -= shift_step | |
| 446 |
else | |
| 447 |
dest := dest translate uInt8 1 ; shift += 8-shift_step | |
| 448 |
eif h<8 and (heads .and. 2^(h+8))=0 | |
| 449 |
for (var Int x) p size_x-1 step space_x | |
| 450 |
var Int l := src map uInt8 | |
| 451 |
if l<>0 | |
| 452 |
var Pointer:Escp2Lut ll :> lut l | |
| 453 |
var Int t := dither map Int x%modulus | |
| 454 |
if ll:big_threshold>=t | |
| 455 |
dest map uInt8 += f:dot_levels*2^shift | |
| 456 |
some := true | |
| 457 |
eif ll:small>=t | |
| 458 |
dest map uInt8 += 2^shift | |
| 459 |
some := true | |
| 460 |
src := src translate uInt8 src_step | |
| 461 |
if shift>0 | |
| 462 |
shift -= shift_step | |
| 463 |
else | |
| 464 |
dest := dest translate uInt8 1 ; shift += 8-shift_step | |
| 465 |
eif h<8 | |
| 466 |
for (var Int x) p size_x-1 step space_x | |
| 467 |
var Int l := src map uInt8 | |
| 468 |
if l<>0 | |
| 469 |
var Pointer:Escp2Lut ll :> lut l | |
| 470 |
var Int t := dither map Int x%modulus | |
| 471 |
if ll:big_threshold>=t | |
| 472 |
dest map uInt8 += f:dot_levels*2^shift | |
| 473 |
some := true | |
| 474 |
eif ll:small>=t and not (ll:light_threshold>=t and not ll:light_removal>=t) | |
| 475 |
dest map uInt8 += 2^shift | |
| 476 |
some := true | |
| 477 |
src := src translate uInt8 src_step | |
| 478 |
if shift>0 | |
| 479 |
shift -= shift_step | |
| 480 |
else | |
| 481 |
dest := dest translate uInt8 1 ; shift += 8-shift_step | |
| 482 |
else # h>=8 | |
| 483 |
for (var Int x) p size_x-1 step space_x | |
| 484 |
var Int l := src map uInt8 | |
| 485 |
if l<>0 | |
| 486 |
var Pointer:Escp2Lut ll :> lut l | |
| 487 |
var Int t := dither map Int x%modulus | |
| 488 |
if ll:light_threshold>=t and not ll:light_removal>=t | |
| 489 |
dest map uInt8 += 2^shift | |
| 490 |
some := true | |
| 491 |
src := src translate uInt8 src_step | |
| 492 |
if shift>0 | |
| 493 |
shift -= shift_step | |
| 494 |
else | |
| 495 |
dest := dest translate uInt8 1 ; shift += 8-shift_step | |
| 496 |
else # advanced | |
| 497 |
var Address dest := output_lines translate uInt8 j*output_line_size+(p\space_x)*bpc\8 | |
| 498 |
var Int shift := 8-bpc-(p\space_x)*bpc%8 | |
| 499 |
var Int shift_step := bpc | |
| 500 |
var Pointer:(Array Escp2Level 256) levels :> f:head:h:level | |
| 501 |
var Pointer:DitherMatrix dither_matrix :> f:head:(h%8):dither | |
| 502 |
var Address dither := addressof (dither_matrix 0 y%dither_matrix:size_y) | |
| 503 |
var Int modulus := dither_matrix size_x | |
| 504 |
for (var Int x) p size_x-1 step space_x | |
| 505 |
var Int l := src map uInt8 | |
| 506 |
if l<>0 | |
| 507 |
var Pointer:Escp2Level level :> levels l | |
| 508 |
var Int d := shunt level:remain>=(dither map Int x%modulus) level:dot1 level:dot0 | |
| 509 |
if d<>0 | |
| 510 |
dest map uInt8 += d*2^shift | |
| 511 |
some := true | |
| 512 |
src := src translate uInt8 src_step | |
| 513 |
if shift>0 | |
| 514 |
shift -= shift_step | |
| 515 |
else | |
| 516 |
dest := dest translate uInt8 1 ; shift += 8-shift_step | |
| 517 |
var Address lines_buffer := output_lines | |
| 518 |
if top_enhancement | |
| 519 |
var Int delta_y := 0 | |
| 520 |
while top+output_y+delta_y*space_y<0 | |
| 521 |
delta_y += 1 | |
| 522 |
lines_buffer := lines_buffer translate Byte delta_y*output_line_size | |
| 523 |
lines_count -= delta_y | |
| 524 |
if lines_count>0 and some | |
| 525 |
if (options option "escp2_fill") and lines_count<jets | |
| 526 |
memory_move lines_buffer output_lines lines_count*output_line_size | |
| 527 |
lines_buffer := output_lines | |
| 528 |
memory_clear (lines_buffer translate Byte lines_count*output_line_size) (jets-lines_count)*output_line_size | |
| 529 |
lines_count := jets | |
| 530 |
var Str cmd := "" | |
| 531 |
if vpos | |
| 532 |
if top_enhancement | |
| 533 |
cmd += escp2 "V" (num2_or_4 coord4 top+output_y+delta_y*space_y) | |
| 534 |
else | |
| 535 |
cmd += escp2 "V" (num2_or_4 coord4 top+output_y) | |
| 536 |
vpos := false | |
| 537 |
if coord4 | |
| 538 |
cmd += escp2 "$" (num4 left+p) | |
| 539 |
else | |
| 540 |
cmd += escape+"$"+(num2 left+p) | |
| 541 |
if not f:old | |
| 542 |
cmd += escape+"i"+character:(shunt h=0 2 h=1 1 h=2 4 h=3 (shunt (command option "matte_black") (shunt (options option "escp2_matte") 0 40h) 0) h<8 h+3 h=8 18 h=9 17 h=10 20 h=11 16 0)+character:(shunt packbits 1 0)+character:bpc+num2:output_line_size+num2:lines_count | |
| 543 |
else | |
| 544 |
cmd += escape+"r"+character:(shunt h=0 2 h=1 1 h=2 4 h=3 0 h=8 18 h=9 17 h=10 20 h=11 16 0) | |
| 545 |
cmd += escape+"."+character:(shunt packbits 1 0)+(num1 3600\(dpi_y\space_y))+(num1 3600\(dpi_x\space_x))+num1:lines_count+(num2 output_line_size*8\bpc) | |
| 546 |
var Address data ; var Int length | |
| 547 |
if packbits | |
| 548 |
data := buffer | |
| 549 |
length := packbits_encode lines_buffer buffer lines_count*output_line_size | |
| 550 |
else | |
| 551 |
data := lines_buffer | |
| 552 |
length := lines_count*output_line_size | |
| 553 |
if top_enhancement and delta_y<>0 | |
| 554 |
var Int i := top+output_y+delta_y*space_y | |
| 555 |
if i>=top_lines:size | |
| 556 |
top_lines size := i+1 | |
| 557 |
top_lines i += cmd | |
| 558 |
(var Str lbuf) set data length false | |
| 559 |
top_lines i += lbuf | |
| 560 |
top_lines i += "[cr]" | |
| 561 |
else | |
| 562 |
if top_enhancement and top_lines:size>0 | |
| 563 |
for (var Int i) 0 (min top+output_y top_lines:size-1) | |
| 564 |
if (exists top_lines:i:first) | |
| 565 |
var Pointer:Str ptr :> top_lines:i first | |
| 566 |
while exists:ptr | |
| 567 |
s writechars ptr | |
| 568 |
ptr :> top_lines:i next ptr | |
| 569 |
top_lines i := var List:Str empty_list | |
| 570 |
if top+output_y>=top_lines:size | |
| 571 |
top_lines size := 0 | |
| 572 |
s writechars cmd | |
| 573 |
s raw_write data length | |
| 574 |
s writechars "[cr]" | |
| 575 |
# ajust the number of pass already done for each line, then drop the input lines we will not use anymore | |
| 576 |
for (var Int j) 0 jets-1 | |
| 577 |
var Int y := output_y+j*space_y | |
| 578 |
check ((pass y+delta) .and. 2^p)=0 | |
| 579 |
pass y+delta += 2^p | |
| 580 |
for (var Int y) output_y-2 output_y+jets\space_x-2 # -2 instead of -1 because output_y may later be decreased by one | |
| 581 |
if y>=0 and y<size_y | |
| 582 |
memory_free f:input_line:y | |
| 583 |
f:input_line y := null | |
| 584 |
output_y := output_y+jets\space_x | |
| 585 |
status := success | |
| 586 |
| |
| 587 |
| |
| 588 |
method f close -> status | |
| 589 |
arg_rw ImageWriteFilterEscp2 f ; arg ExtendedStatus status | |
| 590 |
# send printer termination commands | |
| 591 |
implicit f | |
| 592 |
for (var Int y) 0 size_y-1 | |
| 593 |
check (pass y+delta)=2^space_x-1 | |
| 594 |
if f:input_line:y<>null | |
| 595 |
memory_free f:input_line:y | |
| 596 |
var Pointer:Stream s :> f stream | |
| 597 |
s writechars character:0Ch | |
| 598 |
s writechars escape+"@" | |
| 599 |
if f:job_ticket | |
| 600 |
s writechars (escp2 "R" "[0]REMOTE1") | |
| 601 |
if (f:options option "escp2_je") | |
| 602 |
s writechars (remote "JE" "[0]") # job end | |
| 603 |
s writechars (remote "LD" "") | |
| 604 |
s writechars escape+"[0][0][0]" | |
| 605 |
memory_free f:output_lines | |
| 606 |
memory_free f:buffer | |
| 607 |
if verbose | |
| 608 |
console (repeat 60 " ")+"[cr]" | |
| 609 |
status := success | |
| 610 |
| |
| 611 |
| |
| 612 |
image_record_filters ".escp2" Void false ImageWriteFilterEscp2 false | |
| 613 |
export escp2_generator | |
| |