wok rev 18237

sane-backends: add tazpanel/sane.cgi
author Pascal Bellard <pascal.bellard@slitaz.org>
date Sat Jul 25 13:48:18 2015 +0200 (2015-07-25)
parents aed847cc1e45
children 0294a9dd5215
files sane-backends/receipt sane-backends/stuff/tazpanel/crop.js sane-backends/stuff/tazpanel/sane.cgi
line diff
     1.1 --- a/sane-backends/receipt	Fri Jul 24 15:13:34 2015 +0300
     1.2 +++ b/sane-backends/receipt	Sat Jul 25 13:48:18 2015 +0200
     1.3 @@ -13,11 +13,11 @@
     1.4  DEPENDS="libusb-compat jpeg tiff zlib libgphoto2 libv4l libltdl"
     1.5  BUILD_DEPENDS="libusb-compat-dev jpeg-dev tiff-dev zlib-dev libv4l-dev \
     1.6  libgphoto2-dev libtool"
     1.7 +SUGGESTED="imagemagick gocr tesseract-ocr"
     1.8  
     1.9  # Rules to configure and make the package.
    1.10  compile_rules()
    1.11  {
    1.12 -	cd $src
    1.13  	patch -Np1 -i $stuff/libv4l-0.8.3.patch
    1.14  	# fix https://bugs.archlinux.org/task/26114
    1.15  	patch -Np1 -i $stuff/xerox_mfp_fix_usb_devices.patch
    1.16 @@ -38,7 +38,9 @@
    1.17  genpkg_rules()
    1.18  {
    1.19  	mkdir -p $fs/usr/lib $fs/usr/share \
    1.20 -	         $fs/var/lock/sane $fs/etc/sane.d
    1.21 +	         $fs/var/lock/sane $fs/etc/sane.d \
    1.22 +	         $fs/var/www/tazpanel/lib \
    1.23 +	         $fs/var/www/tazpanel/menu.d/hardware
    1.24  	
    1.25  	cp -a $install/etc/sane.d $fs/etc
    1.26  	cp -a $install/usr/bin $fs/usr
    1.27 @@ -46,6 +48,9 @@
    1.28  	cp -a $install/usr/lib/*.so* $fs/usr/lib
    1.29  	cp -a $install/usr/lib/sane $fs/usr/lib
    1.30  	cp -a $install/usr/share/sane $fs/usr/share
    1.31 +	cp $stuff/tazpanel/sane.cgi $fs/var/www/tazpanel/
    1.32 +	cp $stuff/tazpanel/crop.js $fs/var/www/tazpanel/lib/
    1.33 +	ln -s ../../sane.cgi $fs/var/www/tazpanel/menu.d/hardware/sane
    1.34  	
    1.35  	# fix groups/permissions on /var/lock/sane ; add it to scanner group
    1.36  	chmod 775 "$fs/var/lock/sane"
    1.37 @@ -68,6 +73,9 @@
    1.38  	fi
    1.39  	
    1.40  	echo " ADD yourself to group scanner to use sane: addgroup tux scanner"
    1.41 +	
    1.42 +	[ -e $root/var/www/tazpanel/tmp ] ||
    1.43 +	ln -s /tmp $root/var/www/tazpanel/tmp
    1.44  }
    1.45  
    1.46  post_remove()
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/sane-backends/stuff/tazpanel/crop.js	Sat Jul 25 13:48:18 2015 +0200
     2.3 @@ -0,0 +1,333 @@
     2.4 +var cropOrgWidth, cropOrgHeight, cropX, cropY, cropWidth, cropHeight;
     2.5 +var cropBaseX, cropBaseY, cropDot2value, cropMinSize, cropDragOfs;
     2.6 +
     2.7 +var cropEventX, cropEventY;
     2.8 +var cropResizeId, cropEventTop, cropEventLeft, cropEventWidth, cropEventHeight;
     2.9 +var cropResizeCounter = -1, cropMoveCounter = -1;
    2.10 +
    2.11 +var cropDivW, cropDivN, cropDivE, cropDivS, cropDivFrame;
    2.12 +var cropNW, cropN, cropNE, cropW, cropE, cropSW, cropS, cropSE; 
    2.13 +
    2.14 +function cropOpacity(div,degree)
    2.15 +{
    2.16 +	div.style.backgroundColor = '#FFF';
    2.17 +	if (div.style.opacity) div.style.opacity = degree / 100;
    2.18 +	if (div.style.MozOpacity) div.style.MozOpacity = degree / 101;
    2.19 +	if (div.style.KhtmlOpacity) div.style.KhtmlOpacity = degree / 100;
    2.20 +}
    2.21 +
    2.22 +function cropCreateDiv(e)
    2.23 +{
    2.24 +	var div = document.createElement('DIV');
    2.25 +	div.style.position = 'absolute';
    2.26 +	div.style.visibility = 'visible';
    2.27 +	cropOpacity(div,60);
    2.28 +	div.style.left= div.style.top= div.style.height= div.style.width= '0px';
    2.29 +	div.innerHTML = '<span></span>';
    2.30 +	e.appendChild(div);
    2.31 +	return div;
    2.32 +}
    2.33 +
    2.34 +function cropCreateDragImg(id)
    2.35 +{
    2.36 +	var div = document.createElement('IMG');
    2.37 +	div.src = 'drag.gif';
    2.38 +	div.width = 12;
    2.39 +	div.style.position = 'absolute';
    2.40 +	div.style.cursor = div.id = id;
    2.41 +	div.onmousedown = cropInitResize;
    2.42 +	cropDivFrame.appendChild(div);
    2.43 +	return div;
    2.44 +}
    2.45 +
    2.46 +function cropSetFrame()
    2.47 +{
    2.48 +	var top = cropDivFrame.style.top.replace('px','');
    2.49 +	var left = cropDivFrame.style.left.replace('px','');
    2.50 +	var width = cropDivFrame.style.width.replace('px','');
    2.51 +	var height = cropDivFrame.style.height.replace('px','');
    2.52 +	var totalTop = top/1 + height/1;
    2.53 + 	var totalWidth = left/1 + width/1;
    2.54 +	
    2.55 +	cropN.style.left =
    2.56 +	cropS.style.left = (Math.floor(width/2) - cropDragOfs) + 'px';
    2.57 +	cropE.style.left =
    2.58 +	cropNE.style.left =
    2.59 +	cropSE.style.left = (width - cropDragOfs) + 'px';
    2.60 +	cropW.style.top = 
    2.61 +	cropE.style.top = (Math.floor(height/2) - cropDragOfs) + 'px';
    2.62 +	cropS.style.top =
    2.63 +	cropSE.style.top =
    2.64 +	cropSW.style.top = (height - cropDragOfs) + 'px';
    2.65 +	
    2.66 +	cropDivS.style.height = Math.max(0,cropOrgHeight - totalTop) + 'px';
    2.67 +	cropDivN.style.height = cropDivFrame.style.top;
    2.68 +	cropDivS.style.width = 
    2.69 +	cropDivN.style.width = width + 'px' ;
    2.70 +	cropDivE.style.width = Math.max(0,cropOrgWidth - totalWidth) + 'px';
    2.71 +	cropDivW.style.width =
    2.72 +	cropDivS.style.left = 
    2.73 +	cropDivN.style.left = cropDivFrame.style.left;
    2.74 +	cropDivE.style.left = totalWidth + 'px';
    2.75 +	cropDivS.style.top = totalTop + 'px';
    2.76 +}
    2.77 +
    2.78 +function cropSaveEvent(e)
    2.79 +{
    2.80 +	cropEventX = e.clientX;
    2.81 +	cropEventY = e.clientY;
    2.82 +	cropEventTop = cropDivFrame.style.top.replace('px','');
    2.83 +	cropEventLeft = cropDivFrame.style.left.replace('px','');
    2.84 +	cropEventWidth = cropDivFrame.style.width.replace('px','');
    2.85 +	cropEventHeight = cropDivFrame.style.height.replace('px','');
    2.86 +}
    2.87 +
    2.88 +function cropTimerMove()
    2.89 +{
    2.90 +	if (cropMoveCounter >= 0 && cropMoveCounter < 10) {
    2.91 +		cropMoveCounter++;
    2.92 +		setTimeout('cropTimerMove()',1);
    2.93 +	}		
    2.94 +}
    2.95 +
    2.96 +function cropTimerResize()
    2.97 +{
    2.98 +	if (cropResizeCounter >= 0 && cropResizeCounter < 10) {
    2.99 +		cropResizeCounter++;
   2.100 +		setTimeout('cropTimerResize()',1);
   2.101 +	}
   2.102 +}
   2.103 +
   2.104 +function cropCancelEvent(e)
   2.105 +{
   2.106 +	if (document.all) e = event;
   2.107 +	if (e.target) source = e.target;
   2.108 +	else if (e.srcElement) source = e.srcElement;
   2.109 +	if (source.tagName && source.tagName.toLowerCase() == 'input')
   2.110 +		return true;
   2.111 +	return false;
   2.112 +}
   2.113 +
   2.114 +function cropInitMove(e)
   2.115 +{
   2.116 +	if (document.all) e = event;
   2.117 +	if (e.target) source = e.target;
   2.118 +	else if (e.srcElement) source = e.srcElement;
   2.119 +	if (source.id && source.id.indexOf('resize') >= 0) return;	
   2.120 +	cropSaveEvent(e);
   2.121 +	cropMoveCounter = 0;
   2.122 +	cropTimerMove();
   2.123 +	return false;
   2.124 +}
   2.125 +
   2.126 +var cropDiv0style;
   2.127 +function cropInitResize(e)
   2.128 +{
   2.129 +	if (document.all) e = event;
   2.130 +	cropDivFrame.style.cursor = 'default';
   2.131 +	if (document.all) cropDiv0style.display = 'none';
   2.132 +	cropResizeId = this.id;
   2.133 +	cropResizeCounter = 0;
   2.134 +	cropSaveEvent(e);
   2.135 +	cropTimerResize();
   2.136 +	return false;
   2.137 +}
   2.138 +
   2.139 +var cropMouseMoveEventInProgress = false;
   2.140 +function cropMouseMove(e)
   2.141 +{
   2.142 +	if (cropMouseMoveEventInProgress) return;
   2.143 +	if (cropMoveCounter < 10 && cropResizeCounter < 10) return;
   2.144 +	if (document.all) cropMouseMoveEventInProgress = true;
   2.145 +	if (document.all) e = event;
   2.146 +	var deltaX = e.clientX - cropEventX;
   2.147 +	var deltaY = e.clientY - cropEventY;
   2.148 +	if (cropResizeCounter == 10) {
   2.149 +		var top = cropEventTop;
   2.150 +		var left = cropEventLeft;
   2.151 +		var width = cropEventWidth;
   2.152 +		var height = cropEventHeight;
   2.153 +		if (cropResizeId == 'e-resize'
   2.154 +		 || cropResizeId == 'ne-resize'
   2.155 +		 || cropResizeId == 'se-resize') {
   2.156 +			width = Math.max(cropMinSize,
   2.157 +				cropEventWidth/1 + deltaX/1);
   2.158 +		}
   2.159 +		if (cropResizeId == 's-resize'
   2.160 +		 || cropResizeId == 'sw-resize'
   2.161 +		 || cropResizeId == 'se-resize') {
   2.162 +			height = Math.max(cropMinSize,
   2.163 +				cropEventHeight/1 + deltaY/1);
   2.164 +		}
   2.165 +		if (cropResizeId == 'w-resize'
   2.166 +		 || cropResizeId == 'sw-resize'
   2.167 +		 || cropResizeId == 'nw-resize') {
   2.168 +		 	var total = left/1 + width/1;
   2.169 +			left = Math.min(left/1 + deltaX/1, total - cropMinSize);
   2.170 +			width = total - left;
   2.171 +		}
   2.172 +		
   2.173 +		if (cropResizeId == 'n-resize'
   2.174 +		 || cropResizeId == 'nw-resize'
   2.175 +		 || cropResizeId == 'ne-resize') {
   2.176 +			var total = top/1 + height/1;
   2.177 +			top = Math.min(top/1 + deltaY/1, total - cropMinSize);
   2.178 +			height = total - top;
   2.179 +		}
   2.180 +		
   2.181 +		if (top > cropOrgHeight) height = cropOrgHeight - top;
   2.182 +		if (left > cropOrgWidth) width  = cropOrgWidth - left;
   2.183 +		
   2.184 +		cropDivFrame.style.top = top + 'px';
   2.185 +		cropDivFrame.style.left = left + 'px';
   2.186 +		cropDivFrame.style.width = width + 'px';
   2.187 +		cropDivFrame.style.height = height + 'px';
   2.188 +	}
   2.189 +	
   2.190 +	if (cropMoveCounter == 10) {
   2.191 +		var left = cropEventLeft/1 + deltaX/1;
   2.192 +		var leftMax = cropOrgWidth - cropEventWidth;
   2.193 +		if (left < 0) left = 0;
   2.194 +		if (left > leftMax) left = leftMax;
   2.195 +		cropDivFrame.style.left = left + 'px';
   2.196 +		var top = cropEventTop/1 + deltaY/1;
   2.197 +		var topMax = cropOrgHeight - cropEventHeight;
   2.198 +		if (top < 0) top = 0;
   2.199 +		if (top > topMax) top = topMax;
   2.200 +		cropDivFrame.style.top = top + 'px';
   2.201 +	}
   2.202 +	cropSetFrame();		
   2.203 +	cropMouseMoveEventInProgress = false;
   2.204 +}
   2.205 +
   2.206 +function cropUpdateFromValues()
   2.207 +{
   2.208 +	cropX.value = Math.round(10 * cropDot2value 
   2.209 +		* cropDivFrame.style.left.replace('px','')) /10 
   2.210 +		+ cropBaseX/1;
   2.211 +	cropY.value = Math.round(10 * cropDot2value 
   2.212 +		* cropDivFrame.style.top.replace('px','')) /10 
   2.213 +		+ cropBaseY/1;
   2.214 +	cropWidth.value = Math.round(10 * cropDot2value 
   2.215 +		* cropDivFrame.style.width.replace('px','')) /10;
   2.216 +	cropHeight.value = Math.round(10 * cropDot2value 
   2.217 +		* cropDivFrame.style.height.replace('px','')) /10;
   2.218 +}
   2.219 +
   2.220 +function cropStopResizeMove()
   2.221 +{
   2.222 +	cropMoveCounter = cropResizeCounter = -1;
   2.223 +	cropDivFrame.style.cursor = 'move';
   2.224 +	cropUpdateFromValues();
   2.225 +	if (document.all) cropDiv0style.display = 'block';
   2.226 +}
   2.227 +
   2.228 +function cropGetInput(obj,origin,ofs,min,max)
   2.229 +{
   2.230 +	var t = origin;
   2.231 +	if (obj.value.length)
   2.232 +		t = (obj.value.replace(/[^0-9\.]/gi,'') - ofs) / cropDot2value;
   2.233 +	if (t < min) t = min;
   2.234 +	if (t > max) t = max;
   2.235 +	obj.value = Math.round(t * cropDot2value * 10) /10;
   2.236 +	return Math.round(t);
   2.237 +}
   2.238 +
   2.239 +function cropSetFrameByInput()
   2.240 +{
   2.241 +	var x, y;
   2.242 +	x = cropGetInput(cropX, 0, cropBaseX, 0, cropOrgWidth - cropMinSize);
   2.243 +	y = cropGetInput(cropY, 0, cropBaseY, 0, cropOrgHeight - cropMinSize);
   2.244 +	cropDivFrame.style.top = y + 'px';
   2.245 +	cropDivFrame.style.left = x + 'px';
   2.246 +	cropDivFrame.style.width = cropGetInput(cropWidth, cropOrgWidth, 0, 
   2.247 +					cropMinSize, cropOrgWidth - x) + 'px';
   2.248 +	cropDivFrame.style.height = cropGetInput(cropHeight, cropOrgHeight, 0, 
   2.249 +					cropMinSize, cropOrgHeight - y) + 'px';
   2.250 +	cropSetFrame();		
   2.251 +}
   2.252 +
   2.253 +function cropInit(e,x,y,width,height)
   2.254 +{
   2.255 +	var div = e.parentNode;
   2.256 +	
   2.257 +	cropOrgWidth = e.width;
   2.258 +	cropOrgHeight = e.height;
   2.259 +	
   2.260 +	cropX = document.getElementById(x);
   2.261 +	cropY = document.getElementById(y);
   2.262 +	cropWidth = document.getElementById(width);
   2.263 +	cropHeight = document.getElementById(height);
   2.264 +	
   2.265 +	cropBaseX = cropX.value.replace(/[^0-9\.]/gi,'');
   2.266 +	cropBaseY = cropY.value.replace(/[^0-9\.]/gi,'');
   2.267 +	
   2.268 +	cropDot2value = cropWidth.value / e.width;
   2.269 +	
   2.270 +	div.style.position = 'relative';
   2.271 +	div.style.top = div.style.left = '0px';
   2.272 +	div.style.width = div.style.height = '100%';
   2.273 +	cropOpacity(div,0);
   2.274 +
   2.275 +	cropDivW = cropCreateDiv(div);
   2.276 +	cropDivN = cropCreateDiv(div);
   2.277 +	cropDivE = cropCreateDiv(div);
   2.278 +	cropDivS = cropCreateDiv(div);
   2.279 +	cropDivN.style.width = cropDivE.style.left = 
   2.280 +	cropDivS.style.width = cropOrgWidth + 'px';
   2.281 +	cropDivW.style.height = cropDivE.style.height = 
   2.282 +	cropDivS.style.top = cropOrgHeight + 'px';
   2.283 +	
   2.284 +	cropDivFrame = document.createElement('DIV');
   2.285 +	cropDivFrame.style.border = '1px #000000 dashed';
   2.286 +	cropDivFrame.style.zIndex = 1000;
   2.287 +	cropDivFrame.style.position = 'absolute';
   2.288 +	cropDivFrame.style.left = cropDivFrame.style.top = '0px';
   2.289 +	cropDivFrame.style.width = cropOrgWidth + 'px';
   2.290 +	cropDivFrame.style.height = cropOrgHeight + 'px';
   2.291 +	cropDivFrame.innerHTML = '<div></div>'; 
   2.292 +	cropDivFrame.style.cursor = 'move';
   2.293 +
   2.294 +	cropDiv0style = cropDivFrame.getElementsByTagName('DIV')[0].style;
   2.295 +	if (navigator.userAgent.indexOf('Opera') >=0 ) {
   2.296 +		cropDiv0style.backgroundColor =
   2.297 +		cropDivS.style.backgroundColor =
   2.298 +		cropDivE.style.backgroundColor =
   2.299 +		cropDivN.style.backgroundColor =
   2.300 +		cropDivW.style.backgroundColor = 'transparent';
   2.301 +	}
   2.302 +	
   2.303 +	cropNW = cropCreateDragImg('nw-resize');
   2.304 +	cropNE = cropCreateDragImg('ne-resize');
   2.305 +	cropSW = cropCreateDragImg('sw-resize');
   2.306 +	cropSE = cropCreateDragImg('se-resize');
   2.307 +	cropN = cropCreateDragImg('n-resize');
   2.308 +	cropS = cropCreateDragImg('s-resize');
   2.309 +	cropW = cropCreateDragImg('w-resize');
   2.310 +	cropE = cropCreateDragImg('e-resize');
   2.311 +	cropMinSize = cropE.width*2;
   2.312 +	cropDragOfs = Math.floor(cropE.width/2) 
   2.313 +
   2.314 +	cropN.style.left = cropS.style.left = 
   2.315 +		(Math.floor(cropOrgWidth/2) - cropDragOfs) + 'px';
   2.316 +	cropSW.style.top = cropSE.style.top = 
   2.317 +	cropS.style.top = (cropOrgHeight - cropDragOfs) + 'px';
   2.318 +	
   2.319 +	cropNW.style.top = cropNW.style.left = 
   2.320 +	cropNE.style.top = cropSW.style.left = 
   2.321 +	cropN.style.top  = cropW.style.left = (-cropDragOfs) + 'px';
   2.322 +	
   2.323 +	cropNE.style.left = cropSE.style.left =
   2.324 +	cropE.style.left = (cropOrgWidth - cropDragOfs) + 'px';
   2.325 +	cropW.style.top = cropE.style.top = 
   2.326 +		(Math.floor(cropOrgHeight/2) - cropDragOfs) + 'px';
   2.327 +	
   2.328 +	div.appendChild(cropDivFrame); 
   2.329 +	
   2.330 +	div.onselectstart = div.ondragstart = cropCancelEvent;
   2.331 +	div.onmousemove = cropMouseMove;
   2.332 +	div.onmouseup = cropStopResizeMove;
   2.333 +	cropDivFrame.onmousedown = cropInitMove;
   2.334 +	cropX.onchange = cropY.onchange = cropWidth.onchange =
   2.335 +	cropHeight.onchange = cropSetFrameByInput;
   2.336 +}
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/sane-backends/stuff/tazpanel/sane.cgi	Sat Jul 25 13:48:18 2015 +0200
     3.3 @@ -0,0 +1,382 @@
     3.4 +#!/bin/sh
     3.5 +#
     3.6 +# Scanner CGI interface - Scan documents via a browser
     3.7 +#
     3.8 +# (C) 2015 SliTaz GNU/Linux - BSD License
     3.9 +#
    3.10 +
    3.11 +# Common functions from libtazpanel
    3.12 +. lib/libtazpanel
    3.13 +get_config
    3.14 +
    3.15 +#------
    3.16 +# menu
    3.17 +#------
    3.18 +
    3.19 +case "$1" in
    3.20 +	menu)
    3.21 +		TEXTDOMAIN_original=$TEXTDOMAIN
    3.22 +		export TEXTDOMAIN='sane'
    3.23 +
    3.24 +		cat <<EOT
    3.25 +<li><a data-icon="text" href="sane.cgi"$(groups | grep -q scanner ||
    3.26 +echo ' data-root')>$(_ 'Scanner')</a></li>
    3.27 +EOT
    3.28 +		export TEXTDOMAIN=$TEXTDOMAIN_original
    3.29 +		exit
    3.30 +esac
    3.31 +
    3.32 +TITLE="$(_ 'TazPanel - Hardware') - $(_ 'Scanner')"
    3.33 +
    3.34 +inrange() {
    3.35 +	local n=$1
    3.36 +	[ $1 -lt $2 ] && n=$2
    3.37 +	[ $1 -gt $3 ] && n=$3
    3.38 +	echo $n
    3.39 +}
    3.40 +    
    3.41 +getgeometry() {
    3.42 +	CMD=""
    3.43 +	for i in l t x y ; do
    3.44 +		j=$(inrange $(xPOST geometry_$i) $(xPOST ${i}_min) $(xPOST ${i}_max))
    3.45 +		eval "geometry_$i=$j"
    3.46 +		CMD="$CMD -$i $j"
    3.47 +# convert -crop XxY+L+T -resize XxY
    3.48 +	done
    3.49 +	for i in mode source contrast brightness ; do
    3.50 +		[ "$(xPOST $i)" ] && CMD="$CMD --$i '$(xPOST $i)'"
    3.51 +	done
    3.52 +	resolution=${1:-0}
    3.53 +	if [ $resolution -eq 0 ]; then
    3.54 +		resolution=$(xPOST res_min)
    3.55 +		width=$(GET width)
    3.56 +		[ ${geometry_x:-0} -le 0 ] && geometry_x=$(xPOST x_max)
    3.57 +		while [ $((${resolution:=150} * ${geometry_x%.*})) -lt ${width:-8192} ]; do
    3.58 +			resolution=$(($resolution * 2))
    3.59 +		done
    3.60 +	fi
    3.61 +	[ -d tmp ] || ln -s /tmp tmp
    3.62 +	case "$device" in
    3.63 +	fake*)	echo "cat /usr/share/images/slitaz-background.jpg" ;;
    3.64 +	*)	echo "scanimage -d '$(echo $device | sed 's/,.*//')' --resolution '$(inrange $resolution $(xPOST res_min) $(xPOST res_max))dpi'$CMD"
    3.65 +	esac
    3.66 +}
    3.67 +
    3.68 +imgformat() {
    3.69 +tmp=$(mktemp -u -t tazsane.XXXXXX)
    3.70 +while read key name type exe pkg cmd ; do
    3.71 +	case "$key" in
    3.72 +	\#*)	continue
    3.73 +	esac
    3.74 +	case "$1" in
    3.75 +	list)
    3.76 +		echo -n "<option value=\"$key\""
    3.77 +		[ "$(which $exe 2> /dev/null)" ] || 
    3.78 +		echo -n " disabled title=\"$exe not found: install $pkg\""
    3.79 +		[ "$key" == "pnm" ] &&
    3.80 +		echo -n " title=\"not supported by most browsers\""
    3.81 +		echo ">$key" ;;
    3.82 +	*)
    3.83 +		case "$key" in
    3.84 +		$(xPOST format)|'*')
    3.85 +			case "$HTTP_USER_AGENT" in
    3.86 +
    3.87 +			# Tazweb has no download support
    3.88 +			TazWe*)	rm -f /tmp/$name
    3.89 +				eval "$(getgeometry $(xPOST resolution)) $cmd >/tmp/$name" 2> $tmp.err
    3.90 +				if [ -s /tmp/$name ]; then
    3.91 +					info="Stored in /tmp/$name ($(stat -c %s /tmp/$name) bytes)."
    3.92 +				else
    3.93 +					error="$(sed 's|$|<br />|' $tmp.err)"
    3.94 +					[ "$error" ] || error="I/O error"
    3.95 +				fi
    3.96 +				rm -f $tmp.* ;;
    3.97 +
    3.98 +			# Others should work
    3.99 +			*)	header	"Content-Type: $type" \
   3.100 +					"Content-Disposition: attachment; filename=$name" \
   3.101 +
   3.102 +				eval "$(getgeometry $(xPOST resolution)) $cmd"
   3.103 +				rm -f $tmp.*
   3.104 +				exit ;;
   3.105 +			esac ;;
   3.106 +		esac ;;
   3.107 +	esac
   3.108 +done <<EOT
   3.109 +png		tazsane.png		image/png		convert		imagemagick 	> $tmp.pnm; convert $tmp.pnm png:-
   3.110 +jpeg		tazsane.jpg		image/jpeg		convert		imagemagick 	> $tmp.pnm; convert $tmp.pnm jpg:-
   3.111 +jpeg2000	tazsane.jp2		image/jpeg2000-image	convert		imagemagick 	> $tmp.pnm; convert $tmp.pnm jp2:-
   3.112 +tiff		tazsane.tiff		image/tiff		convert		imagemagick 	> $tmp.pnm; convert $tmp.pnm tiff:-
   3.113 +ps		tazsane.ps		application/postscript	convert		imagemagick 	> $tmp.pnm; convert -page A4+0+0 $tmp.pnm ps:-
   3.114 +pdf		tazsane.pdf		image/pdf		convert		imagemagick 	> $tmp.pnm; convert $tmp.pnm pdf:-
   3.115 +ocr1		tazsane-OCR1.txt	text/plain		gocr		gocr		| gocr -
   3.116 +ocr2		tazsane-OCR2.txt	text/plain		tesseract	tesseract-ocr	| tesseract stdin stdout
   3.117 +pnm		tazsane.pnm		image/pnm		true		slitaz
   3.118 +EOT
   3.119 +}
   3.120 +
   3.121 +xPOST() {
   3.122 +	[ "$preview" == "reset" ] || POST $@
   3.123 +}
   3.124 +
   3.125 +tmpreview="$(POST tmpreview)"
   3.126 +find tmp/ -name 'tazsane*' -mmin +60 -prune -exec rm -f {} \; 
   3.127 +
   3.128 +device="$(POST device)"
   3.129 +preview="$(POST preview)"
   3.130 +info=""
   3.131 +error=""
   3.132 +
   3.133 +case " $(POST) " in
   3.134 +*\ reset\ *)
   3.135 +	unset device tmpreview
   3.136 +	preview="reset" ;;
   3.137 +*\ preview\ *)
   3.138 +	[ "$tmpreview" ] || tmpreview=$(mktemp -u -t tazsane.XXXXXX).png
   3.139 +	tmp=$(mktemp -u -t tazsane.XXXXXX)
   3.140 +	eval "$(getgeometry)" > $tmp.pnm 2> $tmp.err
   3.141 +	if [ -s "$tmp.pnm" ]; then
   3.142 +		convert $tmp.pnm $tmpreview > /dev/null 2>&1 ||
   3.143 +		cp $tmp.pnm $tmpreview
   3.144 +	else
   3.145 +		error="$(sed 's|$|<br />|' $tmp.err)"
   3.146 +		rm -f $tmpreview
   3.147 +	fi
   3.148 +	rm -f $tmp.pnm $tmp.err ;;
   3.149 +*\ scan\ *)
   3.150 +	imgformat download ;;
   3.151 +esac
   3.152 +
   3.153 +header
   3.154 +xhtml_header
   3.155 +[ -n "$error" ] && msg warn "$error"
   3.156 +[ -n "$info" ] && msg tip "$info"
   3.157 +if [ -z "$device" ]; then
   3.158 +	[ -s sane-fake.log ] && all="$(sed 's/|/\n/g' sane-fake.log)" ||
   3.159 +	all="$(scanimage -f '%d,%v %m|' | sed 's/|/\n/g')"
   3.160 +	case "$(echo "$all" | wc -l)" in
   3.161 +	1)	if [ -z "$all" ]; then
   3.162 +			msg warn 'No scanner found'
   3.163 +			xhtml_footer
   3.164 +			exit 0
   3.165 +		fi
   3.166 +		device="${all%|}" ;;
   3.167 +	*)	cat <<EOT
   3.168 +<section>
   3.169 +	<header>
   3.170 +		<form name="scanner" method="post">
   3.171 +			Scanner
   3.172 +			<select name="device" size=1>
   3.173 +EOT
   3.174 +		echo "$all" | awk -F, '{ if (NF > 0) print "<option value=\"" $0 "\">" 1+i++ " - " $2 }'
   3.175 +		cat <<EOT
   3.176 +			</select>
   3.177 +			<button data-icon="start">$(_ "Continue")</button>
   3.178 +		</form>
   3.179 +	</header>
   3.180 +</section>
   3.181 +EOT
   3.182 +		xhtml_footer
   3.183 +		exit 0 ;;
   3.184 +	esac
   3.185 +fi
   3.186 +
   3.187 +cat <<EOT
   3.188 +<section>
   3.189 +<form name="parameters" method="post">
   3.190 +<script language="JavaScript" type="text/javascript">
   3.191 +<!--
   3.192 +function new_width() {
   3.193 +	document.parameters.action = "?width="+document.width
   3.194 +}
   3.195 +
   3.196 +window.onresize = new_width
   3.197 +new_width()
   3.198 +-->
   3.199 +</script>
   3.200 +
   3.201 +<header>
   3.202 +$(echo $device | sed 's/.*,//')
   3.203 +<div class="float-right">
   3.204 +	<button name="scan" data-icon="start">$(_ "Scan")</button>
   3.205 +	<button name="reset" data-icon="stop">$(_ "Reset")</button>
   3.206 +	<button name="preview" data-icon="view">$(_ "Preview")</button>
   3.207 +</div>
   3.208 +</header>
   3.209 +
   3.210 +<table class="wide" border="2" cellpadding="8" cellspacing="0">
   3.211 +<tr>
   3.212 +<td>Format
   3.213 +<select name="format" size=1>
   3.214 +$(imgformat list)
   3.215 +</select>
   3.216 +</td>
   3.217 +EOT
   3.218 +
   3.219 +if [ "$(xPOST params)" ]; then
   3.220 +	params="$(xPOST params | uudecode)"
   3.221 +else 
   3.222 +	params="$({
   3.223 +cat "$(echo $device | sed 's/,.*//').log" 2> /dev/null ||
   3.224 +scanimage --help -d "$(echo $device | sed 's/,.*//')"
   3.225 +} | awk '
   3.226 +function minmax()
   3.227 +{
   3.228 +	if (match($2,"[0-9]")) {
   3.229 +		i=$2; sub(/\.\..*/,"",i)
   3.230 +		j=$2; sub(/.*\.\./,"",j)
   3.231 +		sub(/\..*/,"",j); sub(/[dm%].*/,"",j)
   3.232 +		k=$0; sub(/.* \[/,"",k); sub(/\].*/,"",k)
   3.233 +		print $1 " " int(k) " " int(i) " " int(j)
   3.234 +	}
   3.235 +}
   3.236 +
   3.237 +function enum()
   3.238 +{
   3.239 +	i=$0
   3.240 +	if (index(i,"|")) {
   3.241 +		sub(/^ *--*[a-z]* */,"",i)
   3.242 +		sub(/dpi .*/,"",i); gsub(/ \[.*\].*/,"",i)
   3.243 +		k=$0; sub(/.* \[/,"",k); sub(/\].*/,"",k)
   3.244 +		gsub(/ /,"=",k)
   3.245 +		print $1 " " k " enum " i
   3.246 +	}
   3.247 +	else minmax()
   3.248 +}
   3.249 +
   3.250 +/Options specific to device/ { parse=1 }
   3.251 +{
   3.252 +	if (parse != 1) next
   3.253 +	if (/\[inactive\]/) next
   3.254 +	if (match("-l-t-x-y", $1)) minmax()
   3.255 +	if (match("--resolution--brightness--contrast--source--mode", $1)) enum()
   3.256 +}
   3.257 +')"
   3.258 +fi
   3.259 +output="$(echo "$params" | while read name def min max ; do
   3.260 +	name="${name##*-}"
   3.261 +	def="${def//=/ }"
   3.262 +	if [ "$min" == "enum" ]; then
   3.263 +		res_min=1000000
   3.264 +		res_max=0
   3.265 +		echo "<td>$name"
   3.266 +		echo -n "<select name=\"$name\" size=1"
   3.267 +		[ "$name" == "resolution" ] && echo -n " onchange=showGeometry()"
   3.268 +		echo ">"
   3.269 +		IFS="|"; set -- $max ; unset IFS
   3.270 +		while [ "$1" ]; do
   3.271 +			echo -n "<option value=\"$1\""
   3.272 +			[ "$(xPOST $name)" == "$1" ] && echo -n " selected"
   3.273 +			[ -z "$(xPOST $name)" -a "$def" == "$1" ] && echo -n " selected"
   3.274 +			echo ">$(_ "$1")"
   3.275 +			if [ "$name" == "resolution" ]; then
   3.276 +				[ $res_max -lt $1 ] && res_max=$1
   3.277 +				[ $res_min -gt $1 ] && res_min=$1
   3.278 +			fi
   3.279 +			shift
   3.280 +		done
   3.281 +		echo "</select>"
   3.282 +	else
   3.283 +		[ "$(xPOST $name)" ] && def=$(xPOST $name)
   3.284 +		[ $def -lt $min ] && def=$min
   3.285 +		[ $def -gt $max ] && def=$max
   3.286 +		f="$(_ "$name")<input name=\"$name\" value=\"$def\""
   3.287 +		u=""
   3.288 +		case "$name" in
   3.289 +		x|y|l|t) cat <<EOT
   3.290 +:${name}_max=$max
   3.291 +<input type="hidden" name="${name}_min" value="$min">
   3.292 +<input type="hidden" name="${name}_max" value="$max">
   3.293 +EOT
   3.294 +			while read name2 n2 id val; do
   3.295 +				[ "$name" == "$name2" ] || continue
   3.296 +				[ "$(xPOST geometry_$name)" ] &&
   3.297 +				val="$(xPOST geometry_$name)"
   3.298 +				f="$(_ "$n2")<input name=\"geometry_$name\" id=\"$id\" value=\"$val\""
   3.299 +				u="&nbsp;mm"
   3.300 +				break
   3.301 +			done <<EOT
   3.302 +l	X-Offset	x	0
   3.303 +t	Y-Offset	y	0
   3.304 +x	Width		width	$max
   3.305 +y	Height		height	$max
   3.306 +EOT
   3.307 +			[ "$newline" ] || echo "</tr><tr>"
   3.308 +			newline=$name
   3.309 +		esac
   3.310 +		[ "$name" == "resolution" ] && f="$f onchange=showGeometry()"
   3.311 +		echo "<td>$f type=\"text\" title=\"$min .. $max\" size=4 maxlength=4>$u"
   3.312 +		res_min=$min
   3.313 +		res_max=$max
   3.314 +	fi
   3.315 +	case "$name" in
   3.316 +	resolution) cat <<EOT
   3.317 +<input type="hidden" name="res_min" value="$res_min">
   3.318 +<input type="hidden" name="res_max" value="$res_max">
   3.319 +&nbsp;dpi
   3.320 +EOT
   3.321 +	esac
   3.322 +	echo "</td>"
   3.323 +done)"
   3.324 +echo "$output" | sed '/^:/d'
   3.325 +
   3.326 +org_x=$(xPOST geometry_x); [ "$org_x" ] || org_x=$(echo "$output" | sed '/^:x_max=/!d;s/.*=//')
   3.327 +org_y=$(xPOST geometry_y); [ "$org_y" ] || org_y=$(echo "$output" | sed '/^:y_max=/!d;s/.*=//')
   3.328 +
   3.329 +cat <<EOT
   3.330 +</tr>
   3.331 +</table>
   3.332 +<input type="hidden" name="tmpreview" value="$tmpreview">
   3.333 +<input type="hidden" name="device" value="$device">
   3.334 +<input type="hidden" name="params" value="$(echo "$params" | uuencode -m -)">
   3.335 +<script language="JavaScript" type="text/javascript">
   3.336 +<!--
   3.337 +function setGeometry(x,y) {
   3.338 +  document.parameters.geometry_x.value = x;
   3.339 +  document.parameters.geometry_y.value = y;
   3.340 +  cropSetFrameByInput();
   3.341 +}
   3.342 +
   3.343 +function showGeometry() {
   3.344 +  var resolution = document.parameters.resolution.value;
   3.345 +  if (resolution) {
   3.346 +    resolution /= 25.4;
   3.347 +    var x = Math.floor(document.parameters.geometry_x.value * resolution);
   3.348 +    var y = Math.floor(document.parameters.geometry_y.value * resolution);
   3.349 +    alert((Math.round(x * y / 100000)/10) + ' Mpixels\n' + x + 'x' + y);
   3.350 +  }
   3.351 +}
   3.352 +-->
   3.353 +</script>
   3.354 +
   3.355 +<footer align="center">
   3.356 +EOT
   3.357 +awk -vox=$org_x -voy=$org_y 'END {
   3.358 +	x=210*4; y=297*4; n=0; cnt=0;
   3.359 +	while (cnt < 9) {
   3.360 +		if (ox +1 >= x && oy +1 >= y) {
   3.361 +    			print "&nbsp;<a href=\"javascript:setGeometry(" x "," y ")\">DIN-A" n "</a>"
   3.362 +    			cnt++
   3.363 +  		}
   3.364 +		if (ox +1 >= x && oy +1 >= y) {
   3.365 +    			print "&nbsp;<a href=\"javascript:setGeometry(" y "," x ")\">DIN-A" n "L</a>"
   3.366 +    			cnt++
   3.367 +  		}
   3.368 +  		tmp=x; x=y/2; y=tmp
   3.369 + 		n++
   3.370 +}
   3.371 +}' < /dev/null
   3.372 +
   3.373 +cat <<EOT
   3.374 +</footer>
   3.375 +</form>
   3.376 +</section>
   3.377 +EOT
   3.378 +
   3.379 +[ -s "$tmpreview" ] && cat <<EOT
   3.380 +<div margin="15px" style="overflow-x: auto">
   3.381 +	<script type="text/javascript" src="lib/crop.js"></script>
   3.382 +	<img src="$tmpreview" onload=cropInit(this,'x','y','width','height')>
   3.383 +</div>
   3.384 +EOT
   3.385 +xhtml_footer