/
ScannerOptions.php
150 lines (127 loc) · 6.12 KB
/
ScannerOptions.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
<?php
class ScannerOption {
public $name = "";
public $values = "";
public $isRange = false;
public $defaultValue = "";
public function isValidValue ($value) {
if ($this->isRange) {
$last = (count($this->values) > 0) ? count($this->values)-1 : 0;
return ($value >= $this->values[0] && $value <= $this->values[$last]);
} else {
return (in_array($value, $this->values));
}
}
}
final class ScannerOptions {
const DEVICES_FILE = "./devices.txt";
const OPTIONS_FILE = "./scanimage.txt";
private static $options = NULL;
public static function getAll() {
if (self::$options == NULL) {
self::$options = self::parseOptions();
}
return self::$options;
}
public static function get($device) {
$scanners = self::getAll();
for ($i = 0; $i < count($scanners); ++$i) {
if ($scanners[$i]["name"] == $device) {
return $scanners[$i];
}
}
return $scanners[0];
}
private static function parseOptions($device = "") {
// Check if file was generated by 'scanimage -L'. Otherwise, invoke it and save output to file
$deviceList = array();
if (file_exists(self::DEVICES_FILE)) {
$deviceList = explode("\n", file_get_contents(self::DEVICES_FILE));
} else {
$deviceList = System::ScannerDevices();
file_put_contents(self::DEVICES_FILE, implode("\n", $deviceList));
}
// Check if file was generated by 'scanimage -A'. Otherwise, invoke it and save output to file
$output = array();
if (file_exists(self::OPTIONS_FILE)) {
$output = explode("\n", file_get_contents(self::OPTIONS_FILE));
} else {
$output = System::ScannerOptions();
file_put_contents(self::OPTIONS_FILE, implode("\n", $deviceList));
}
$scannersPattern = "/^[ ]*device `(.+)' is a (.+)/";
$matchedScanners = preg_grep($scannersPattern, $deviceList);
$scanners = array();
// Store scanner name (key) and description (value)
foreach ($matchedScanners as $matched) {
preg_match($scannersPattern, $matched, $matched);
$name = $matched[1];
$description = $matched[2];
$devices[$name] = $description;
}
$devicePattern = "/[Oo]ptions specific to device `(.+)'/";
$allMatched = "/[ ]*([^\s]+) (.+) (\[.+\])/";
for ($i = 0, $d = -1; $i < count($output); ++$i) {
if (preg_match($devicePattern, $output[$i], $matched)) {
// Just parsed the starting section which contains SANE device name
$scanner = array();
$name = $matched[1];
$scanner["name"] = $name;
$scanner["description"] = $devices[$name];
$scanners[++$d] = $scanner;
} else if (preg_match($allMatched, $output[$i], $matched)) {
// Parsing options for the current SANE device
$option = new ScannerOption();
$key = preg_replace("/^[-]{1,2}/","",$matched[1]);
$option->name = $matched[1];
$option->defaultValue = preg_replace("/(\[|\])/","",$matched[3]);
if (strstr($matched[2],"|")) {
// Fixed set of enumerated values, separated with "|"
$option->values = explode("|",$matched[2]);
$option->isRange = false;
} else if (strstr($matched[2],"..")) {
// Values ranging from low to high, i.e., lo ".." hi
$option->values = explode("..",$matched[2]);
$option->isRange = true;
} else {
// Single element, manually create array
$option->values = array($matched[2]);
$option->isRange = false;
}
// Floor all numerical option values... no reason found to keep
// them as floats
if (is_numeric($option->defaultValue)) {
$option->defaultValue = floor($option->defaultValue);
for ($n = 0; $n < count($option->values); ++$n) $option->values[$n] = floor($option->values[$n]);
}
// Check whether interface accepts a range for resolution and
// enumerate instead. This is to avoid having to make a slider
// for resolution in frontend
if ($option->isRange && $key == "resolution") {
$option->isRange = false;
$increasing = array();
$decreasing = array();
$last = (count($option->values) > 0) ? count($option->values)-1 : 0;
$min = $option->values[0];
$max = $option->values[$last];
$ratio = $max / $min;
// Calculate resolution values as follows
// (1) Start from lower bound and multiply by increasing integers until reaching upper bound
// (2) Start from uppper bound and divide by increasing integers until reaching lower bound
for ($res = 1; $res <= $ratio; ++$res) {
$increasing[] = $min * $res;
$decreasing[] = $max / $res;
}
// Take the intersection of the two resolution arrays from the above
$option->values = array_intersect($increasing, $decreasing);
// Ensure that the default value is also part of the list
if (!in_array($option->defaultValue,$option->values)) $option->values[] = $option->defaultValue;
}
sort($option->values);
$scanners[$d]["options"][$key] = $option;
}
}
return $scanners;
}
}
?>