wok view sane-backends/stuff/tazpanel/sane.cgi @ rev 22061

sane-backends/sane.cgi: add range values
author Pascal Bellard <pascal.bellard@slitaz.org>
date Thu Oct 24 17:12:11 2019 +0200 (2019-10-24)
parents 808a9e7827f1
children
line source
1 #!/bin/sh
2 #
3 # Scanner CGI interface - Scan documents via a browser
4 #
5 # (C) 2015 SliTaz GNU/Linux - BSD License
6 #
8 # Common functions from libtazpanel
9 . lib/libtazpanel
10 get_config
12 #------
13 # menu
14 #------
16 case "$1" in
17 menu)
18 TEXTDOMAIN_original=$TEXTDOMAIN
19 export TEXTDOMAIN='sane'
21 cat <<EOT
22 <li><a data-icon="text" href="sane.cgi"$(groups | grep -q scanner ||
23 echo ' data-root')>$(_ 'Scanner')</a></li>
24 EOT
25 export TEXTDOMAIN=$TEXTDOMAIN_original
26 exit
27 esac
29 TITLE="$(_ 'TazPanel - Hardware') - $(_ 'Scanner')"
31 inrange() {
32 local n=$1
33 [ $1 -lt $2 ] && n=$2
34 [ $1 -gt $3 ] && n=$3
35 echo $n
36 }
38 getgeometry() {
39 CMD=""
40 ARGS=""
41 for i in x y l t ; do
42 j=$(inrange $(xPOST geometry_$i) $(xPOST ${i}_min) $(xPOST ${i}_max))
43 eval "geometry_$i=$j"
44 CMD="$CMD -$i $j"
45 ARGS="$ARGS $j"
46 done
47 for i in $(POST) ; do
48 case $i in
49 preview|format|resolution|res_min|res_max|l_min|l_max);;
50 geometry_l|t_min|t_max|geometry_t|x_min|x_max|geometry_x);;
51 y_min|y_max|geometry_y|tmpreview|device|params);;
52 *) v="$(xPOST $i)"; i="--${i//_/-}"
53 case "$v" in
54 '') ;;
55 yes|no) CMD="$CMD $i=$v" ;;
56 *) CMD="$CMD $i '$v'" ;;
57 esac
58 esac
59 done
60 resolution=${1:-0}
61 if [ $resolution -eq 0 ]; then
62 resolution=$(xPOST res_min)
63 width=$(GET width)
64 [ ${geometry_x:-0} -le 0 ] && geometry_x=$(xPOST x_max)
65 while [ $((${resolution:=150} * ${geometry_x%.*})) -lt ${width:-8192} ]; do
66 resolution=$(($resolution * 2))
67 done
68 fi
69 case "$(xPOST mode)" in
70 *lack*|*ineart*) mode="-monochrome" ;;
71 *ray*) mode="-colorspace gray" ;;
72 *) mode="" ;;
73 esac
74 [ -d tmp ] || ln -s /tmp tmp
75 case "$device" in
76 fake*) f=$(ls fake-sane/*.png | sed q)
77 [ -s "$f" ] || f=/usr/share/images/slitaz-banner.png
78 c="$(echo $ARGS $(identify $f | sed \
79 's/.* \([0-9]*\)x.*/\1/') $(GET width) $(POST x_max) | awk '
80 function a(x) { return int(($x * $5)/ $7); }
81 { printf "%dx%d+%d+%d -resize %dx%d",a(1),a(2),a(3),a(4),$6,int(($2*$6)/$1)}
82 ')"
83 suf="png"; [ "$1" ] && suf="pnm"
84 cat <<EOT
85 if convert -crop $c $mode $f /tmp/sane$$.$suf ; then
86 cat /tmp/sane$$.$suf
87 rm -f /tmp/sane$$.$suf
88 else
89 cat $f
90 fi 2> /dev/null
91 EOT
92 ;;
93 *) echo -n "scanimage -d '$(echo $device | sed 's/,.*//')' --resolution '$(inrange $resolution $(xPOST res_min) $(xPOST res_max))dpi'$CMD"
94 if [ -z "$1" -a "$(which convert)" ]; then
95 echo -n "> /tmp/sane$$.pnm ; convert -resize "
96 echo $ARGS 1024 | awk '{ printf "%dx%d",$5,int(($2*$5)/$1)}'
97 echo -n " /tmp/sane$$.pnm /tmp/sane$$.png ;"
98 echo -n "cat /tmp/sane$$.png ; rm -f /tmp/sane$$.pn?"
99 fi
100 esac
101 }
103 imgformat() {
104 tmp=$(mktemp -u -t tazsane.XXXXXX)
105 pnm2png=convert; pnm2png_cmd="> $tmp.pnm; convert $tmp.pnm png:-"
106 [ "$(which pnm2png)" ] && pnm2png=pnm2png && pnm2png_cmd="|pnm2png"
107 while read key name type exe pkg cmd ; do
108 case "$key" in
109 \#*) continue
110 esac
111 case "$1" in
112 list)
113 echo -n "<option value=\"$key\""
114 disabled=""
115 for i in ${exe//|/ }; do
116 [ "$(which $i 2> /dev/null)" ] ||
117 disabled=" disabled title=\"$i not found: install package $pkg\""
118 done
119 echo -n "$disabled"
120 [ "$key" == "pnm" ] &&
121 echo -n " title=\"not supported by most browsers\""
122 echo ">$key" ;;
123 *)
124 case "$key" in
125 $(xPOST format)|'*')
126 case "$HTTP_USER_AGENT" in
128 # Tazweb has no download support
129 TazWe*) rm -f /tmp/$name
130 eval "$(getgeometry $(xPOST resolution)) $cmd >/tmp/$name" 2> $tmp.err
131 if [ -s /tmp/$name ]; then
132 info="Stored in /tmp/$name ($(stat -c %s /tmp/$name) bytes)."
133 else
134 error="$(sed 's|$|<br />|' $tmp.err)"
135 [ "$error" ] || error="I/O error"
136 fi
137 rm -f $tmp.* ;;
139 # Others should work
140 *) header "Content-Type: $type" \
141 "Content-Disposition: attachment; filename=$name" \
143 eval "$(getgeometry $(xPOST resolution)) $cmd"
144 rm -f $tmp.*
145 exit ;;
146 esac ;;
147 esac ;;
148 esac
149 done <<EOT
150 png tazsane.png image/png $pnm2png imagemagick $pnm2png_cmd
151 jpeg tazsane.jpg image/jpeg convert imagemagick > $tmp.pnm; convert $tmp.pnm jpg:-
152 jpeg2000 tazsane.jp2 image/jpeg2000-image convert imagemagick > $tmp.pnm; convert $tmp.pnm jp2:-
153 tiff tazsane.tiff image/tiff convert imagemagick > $tmp.pnm; convert $tmp.pnm tiff:-
154 ps tazsane.ps application/postscript convert imagemagick > $tmp.pnm; convert -page A4+0+0 $tmp.pnm ps:-
155 pdf tazsane.pdf image/pdf convert imagemagick > $tmp.pnm; convert $tmp.pnm pdf:-
156 ocr1 tazsane-OCR1.txt text/plain gocr gocr | gocr -
157 ocr2 tazsane-OCR2.txt text/plain tesseract tesseract-ocr | tesseract stdin stdout
158 pnm tazsane.pnm image/pnm true slitaz
159 EOT
160 }
162 xPOST() {
163 [ "$preview" == "reset" ] || POST $@
164 }
166 tmpreview="$(POST tmpreview)"
167 find tmp/ -name 'tazsane*' -mmin +60 -prune -exec rm -f {} \;
169 device="$(POST device)"
170 preview="$(POST preview)"
171 info=""
172 error=""
174 case " $(POST) " in
175 *\ reset\ *)
176 unset device tmpreview
177 preview="reset" ;;
178 *\ preview\ *)
179 [ "$tmpreview" ] || tmpreview=$(mktemp -u -t tazsane.XXXXXX).png
180 tmp=$(mktemp -u -t tazsane.XXXXXX)
181 eval "$(getgeometry)" > $tmp.pnm 2> $tmp.err
182 if [ -s "$tmp.pnm" ]; then
183 convert $tmp.pnm $tmpreview > /dev/null 2>&1 ||
184 pnm2png < $tmp.pnm > $tmpreview ||
185 cp $tmp.pnm $tmpreview
186 else
187 error="$(sed 's|$|<br />|' $tmp.err)"
188 rm -f $tmpreview
189 fi
190 rm -f $tmp.pnm $tmp.err ;;
191 *\ scan\ *)
192 imgformat download ;;
193 esac
195 header
196 xhtml_header
197 [ -n "$error" ] && msg warn "$error"
198 [ -n "$info" ] && msg tip "$info"
199 if [ -z "$device" ]; then
200 suggested=""
201 while read exe pkg msg; do
202 [ "$(which $exe 2> /dev/null)" ] && continue
203 suggested="$suggested
204 <li><a href=\"/user/pkgs.cgi?info=$pkg\">$pkg</a>&nbsp;$msg</li>"
205 done <<EOT
206 convert imagemagick $(_ "to preview images and support more image formats (recommended)")
207 gocr gocr $(_ "a basic optical character recognition")
208 tesseract tesseract-ocr $(_ "a better optical character recognition")
209 EOT
210 [ "$suggested" ] &&
211 msg tip "$(_ "You may need to install:") <ol>$suggested</ol>"
212 all="$(scanimage -f '%d,%v %m|'|\
213 cat - sane-fake.log fake-sane/sane-fake.log |sed 's/|/\n/g')"
214 case "$(echo "$all" | wc -l)" in
215 1) if [ -z "$all" ]; then
216 msg warn "$(_ "No scanner found")"
217 msg tip "$(_ "You can test this GUI with ")\
218 <a href=\"/user/pkgs.cgi?info=fake-sane\">fake-sane</a>"
219 xhtml_footer
220 exit 0
221 fi
222 if [ "$suggested" ]; then
223 cat <<EOT
224 <section>
225 <header>
226 <form name="scanner" method="post">
227 <input type="hidden" name="device" value="$all">
228 Scanner ${all#*,}
229 <button data-icon="start">Continue</button>
230 </form>
231 </header>
232 </section>
233 EOT
234 xhtml_footer
235 exit 0
236 fi
237 device="${all%|}" ;;
238 *)
239 cat <<EOT
240 <section>
241 <header>
242 <form name="scanner" method="post">
243 Scanner
244 <select name="device" size=1>
245 EOT
246 echo "$all" | awk -F, '{ if (NF > 0) print "<option value=\"" $0 "\">" 1+i++ " - " $2 }'
247 cat <<EOT
248 </select>
249 <button data-icon="start">$(_ "Continue")</button>
250 </form>
251 </header>
252 </section>
253 EOT
254 xhtml_footer
255 exit 0 ;;
256 esac
257 fi
259 cat <<EOT
260 <section>
261 <form name="parameters" method="post" style="width:100%">
263 <header>
264 $(echo $device | sed 's/.*,//')
265 <div class="float-right">
266 <button name="scan" data-icon="start">$(_ "Scan")</button>
267 <button name="reset" data-icon="refresh">$(_ "Reset")</button>
268 <button name="preview" data-icon="view">$(_ "Preview")</button>
269 </div>
270 </header>
272 <table style="width:100%">
273 <tr>
274 <td title="Sets the file format for the scanned image">
275 <fieldset><legend>$(_ 'Format')</legend>
276 <select name="format" size=1>
277 $(imgformat list)
278 </select>
279 </fieldset>
280 </td>
281 EOT
283 if [ "$(xPOST params)" ]; then
284 params="$(xPOST params | uudecode)"
285 else
286 params="$({
287 cat "$(echo $device | sed 's/,.*//').log" 2> /dev/null ||
288 scanimage --help -d "$(echo $device | sed 's/,.*//')"
289 } | dos2unix | sed 's|\[=| [|;s/||/|/g' | awk '
290 function unit(s)
291 {
292 if (match(s,/[0-9]*mm$/) || match(s,/[0-9]*mm /)) u="mm"
293 else if (match(s,/[0-9]*%$/) || match(s,/[0-9]*% /)) u="%"
294 else if (match(s,/[0-9]*dpi$/) || match(s,/[0-9]*dpi /)) u="dpi"
295 else u="none"
296 }
298 function minmax()
299 {
300 inactive=1
301 if (match($2,"[0-9]")) {
302 i=$2; sub(/\.\..*/,"",i)
303 j=$2; sub(/.*\.\./,"",j)
304 unit(j); sub(/\..*/,"",j); sub(/[dm%].*/,"",j)
305 k=$0; sub(/.* \[/,"",k); sub(/\].*/,"",k)
306 printf("\n%s",$1 " " int(k) " " int(i) " " int(j) " " u)
307 inactive=0
308 }
309 }
311 function enum()
312 {
313 i=$0
314 inactive=1
315 if (index(i,"|")) {
316 sub(/^ *--*[a-z-]* */,"",i)
317 sub(/\[\(/,"",i); sub(/\)\]/,"",i); unit(i)
318 sub(/dpi .*/,"",i); gsub(/ \[.*\].*/,"",i)
319 k=$0; sub(/.* \[/,"",k); sub(/\].*/,"",k)
320 gsub(/ /,"=",k)
321 gsub(/ /,"=",i)
322 printf("\n%s",$1 " " k " enum " i " " u)
323 inactive=0
324 }
325 else minmax()
326 }
328 {
329 if (/scanimage --help/) end=1
330 if (end != 0) next
331 if (/:$/) parse=0
332 if (/[Mm]ode/ || /[Aa]dvanced/ || /[Gg]eometry/) parse=1
333 if (/brightness/ || /contrast/ || /orientation/) parse=1
334 if (parse != 1) next
335 if (/\[inactive\]/) { inactive=1; next }
336 if (/[0-9]\.\.[0-9]/) minmax()
337 else if (/^ --/) enum()
338 else if (!/:$/ && inactive == 0) printf(" %s",$0)
339 } END { print "" }
340 ' | sed 1d)"
341 fi
342 output="$(n=$(echo "$params" | wc -l); echo "$params" | \
343 while read name def min max unit help; do
344 name="${name#-}"
345 name="${name#-}"
346 name="${name//-/_}"
347 help="$(echo $help | sed 's| | |g;s|"|\&#34|g')"
348 def="${def//=/ }"
349 max="${max//=/ }"
350 [ "$unit" = "none" ] && unit=""
351 [ "$name" ] || continue
352 if [ "$min" == "enum" ]; then
353 res_min=1000000
354 res_max=0
355 echo "<td title=\"$help\"><fieldset><legend>$name</legend>"
356 echo -n "<select name=\"$name\" size=1"
357 [ "$name" == "resolution" ] && echo -n " onchange=showGeometry()"
358 echo ">"
359 IFS="|"; set -- $max ; unset IFS
360 while [ "$1" ]; do
361 echo -n "<option value=\"$1\""
362 [ "$(xPOST $name)" == "$1" ] && echo -n " selected"
363 [ -z "$(xPOST $name)" -a "$def" == "$1" ] && echo -n " selected"
364 echo ">$(_ "$1")"
365 if [ "$name" == "resolution" ]; then
366 [ $res_max -lt $1 ] && res_max=$1
367 [ $res_min -gt $1 ] && res_min=$1
368 fi
369 shift
370 done
371 echo "</select>&nbsp;$unit"
372 else
373 [ "$(xPOST $name)" ] && def=$(xPOST $name)
374 [ $def -lt $min ] && def=$min
375 [ $def -gt $max ] && def=$max
376 [ "$idrange" ] || idrange=1
377 f="<fieldset><legend>$(_ "$name")</legend>
378 <input type=\"range\" id=\"range$idrange\" min=\"$min\" max=\"$max\"
379 name=\"$name\" value=\"$def\" onchange=\"updaterange(this)\""
380 u="<div id=\"range$((idrange++))val\">$def${unit+&nbsp;$unit}</div>"
381 case "$name" in
382 x|y|l|t) cat <<EOT
383 :${name}_max=$max
384 <input type="hidden" name="${name}_min" value="$min">
385 <input type="hidden" name="${name}_max" value="$max">
386 EOT
387 while read name2 n2 id val; do
388 [ "$name" == "$name2" ] || continue
389 [ "$(xPOST geometry_$name)" ] &&
390 val="$(xPOST geometry_$name)"
391 f="<fieldset><legend>$(_ "$n2")</legend><input type=\"text\" name=\"geometry_$name\" id=\"$id\" value=\"$val\""
392 u="&nbsp;mm"
393 break
394 done <<EOT
395 l X-Offset x 0
396 t Y-Offset y 0
397 x Width width $max
398 y Height height $max
399 EOT
400 esac
401 [ "$name" == "resolution" ] && f="$f onchange=showGeometry()"
402 echo "<td>$f title=\"$min .. $max. $help\" size=5 maxlength=5>$u"
403 res_min=$min
404 res_max=$max
405 fi
406 case "$name" in
407 resolution) cat <<EOT
408 <input type="hidden" name="res_min" value="$res_min">
409 <input type="hidden" name="res_max" value="$res_max">
410 EOT
411 esac
412 echo "</fieldset></td>"
413 n=$(($n - 2))
414 case "$n" in
415 1|2) echo "</tr><tr>"
416 esac
417 done)"
418 echo "$output" | sed '/^:/d'
420 org_x=$(xPOST geometry_x); [ "$org_x" ] || org_x=$(echo "$output" | sed '/^:x_max=/!d;s/.*=//')
421 org_y=$(xPOST geometry_y); [ "$org_y" ] || org_y=$(echo "$output" | sed '/^:y_max=/!d;s/.*=//')
423 cat <<EOT
424 </tr>
425 </table>
426 <input type="hidden" name="tmpreview" value="$tmpreview">
427 <input type="hidden" name="device" value="$device">
428 <input type="hidden" name="params" value="$(echo "$params" | uuencode -m -)">
429 <script language="JavaScript" type="text/javascript">
430 <!--
431 function setGeometry(x,y) {
432 document.parameters.geometry_x.value = x;
433 document.parameters.geometry_y.value = y;
434 cropSetFrameByInput();
435 }
437 function showGeometry() {
438 var resolution = document.parameters.resolution.value;
439 if (resolution) {
440 resolution /= 25.4;
441 var x = Math.floor(document.parameters.geometry_x.value * resolution);
442 var y = Math.floor(document.parameters.geometry_y.value * resolution);
443 alert((Math.round(x * y / 100000)/10) + ' Mpixels\n' + x + 'x' + y);
444 }
445 }
447 function updaterange(r) {
448 var e=document.getElementById(r.id+"val")
449 if (e) e.innerHTML=e.innerHTML.replace(/[0-9]*/,r.value)
450 }
451 -->
452 </script>
454 <footer align="center">
455 EOT
456 awk -vox=$org_x -voy=$org_y 'END {
457 x=210*4; y=297*4; n=0; cnt=0;
458 while (cnt < 9) {
459 if (ox +1 >= x && oy +1 >= y) {
460 print "&nbsp;<a href=\"javascript:setGeometry(" x "," y ")\">DIN-A" n "</a>"
461 cnt++
462 }
463 if (ox +1 >= x && oy +1 >= y) {
464 print "&nbsp;<a href=\"javascript:setGeometry(" y "," x ")\">DIN-A" n "L</a>"
465 cnt++
466 }
467 tmp=x; x=y/2; y=tmp
468 n++
469 }
470 }' < /dev/null
472 cat <<EOT
473 </footer>
474 </form>
475 </section>
476 EOT
478 [ -s "$tmpreview" ] && cat <<EOT
479 <div margin="15px" style="overflow-x: auto">
480 <script type="text/javascript" src="lib/crop.js"></script>
481 <img src="$tmpreview" style="width:100%" onload=cropInit(this,'x','y','width','height')>
482 </div>
483 EOT
484 xhtml_footer