merged tag ooo/OOO330_m14
[LibreOffice.git] / extensions / source / scanner / sane.cxx
blob43c50e6f84517e87ff9858e4e8277eb56c9fde72
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_extensions.hxx"
30 #include <cstdarg>
31 #include <math.h>
32 #include <osl/file.h>
33 #include <tools/stream.hxx>
34 #include <sane.hxx>
35 #include <dlfcn.h>
36 #include <stdio.h>
37 #include <unistd.h>
38 #include <sys/time.h>
39 #include <sys/types.h>
40 #include <sal/config.h>
42 #if (OSL_DEBUG_LEVEL > 1) || defined DBG_UTIL
43 #include <stdarg.h>
44 #define dump_state( a, b, c, d ) fprintf( stderr, a, b, c, d );
45 #else
46 #define dump_state( a, b, c, d ) ;
47 #endif
48 inline void dbg_msg( const char* pString, ... )
50 #if (OSL_DEBUG_LEVEL > 1) || defined DBG_UTIL
51 va_list ap;
52 va_start( ap, pString );
53 vfprintf( stderr, pString, ap );
54 va_end( ap );
55 #else
56 (void)pString;
57 #endif
60 #define FAIL_SHUTDOWN_STATE( x, y, z ) \
61 if( x != SANE_STATUS_GOOD ) \
62 { \
63 dump_state( "%s returned error %d (%s)\n", \
64 y, x, p_strstatus( x ) ); \
65 DeInit(); \
66 return z; \
69 #define FAIL_STATE( x, y, z ) \
70 if( x != SANE_STATUS_GOOD ) \
71 { \
72 dump_state( "%s returned error %d (%s)\n", \
73 y, x, p_strstatus( x ) ); \
74 return z; \
77 #define DUMP_STATE( x, y ) \
78 if( x != SANE_STATUS_GOOD ) \
79 { \
80 dump_state( "%s returned error %d (%s)\n", \
81 y, x, p_strstatus( x ) ); \
84 #define CHECK_STATE( x, y ) \
85 if( x != SANE_STATUS_GOOD ) \
86 { \
87 dump_state( "%s returned error %d (%s)\n", \
88 y, x, p_strstatus( x ) ); \
89 } \
90 else
92 int Sane::nRefCount = 0;
93 oslModule Sane::pSaneLib = 0;
94 SANE_Int Sane::nVersion = 0;
95 SANE_Device** Sane::ppDevices = 0;
96 int Sane::nDevices = 0;
98 SANE_Status (*Sane::p_init)( SANE_Int*,
99 SANE_Auth_Callback ) = 0;
100 void (*Sane::p_exit)() = 0;
101 SANE_Status (*Sane::p_get_devices)( const SANE_Device***,
102 SANE_Bool ) = 0;
103 SANE_Status (*Sane::p_open)( SANE_String_Const, SANE_Handle ) = 0;
104 void (*Sane::p_close)( SANE_Handle ) = 0;
105 const SANE_Option_Descriptor* (*Sane::p_get_option_descriptor)(
106 SANE_Handle, SANE_Int ) = 0;
107 SANE_Status (*Sane::p_control_option)( SANE_Handle, SANE_Int,
108 SANE_Action, void*,
109 SANE_Int* ) = 0;
110 SANE_Status (*Sane::p_get_parameters)( SANE_Handle,
111 SANE_Parameters* ) = 0;
112 SANE_Status (*Sane::p_start)( SANE_Handle ) = 0;
113 SANE_Status (*Sane::p_read)( SANE_Handle, SANE_Byte*, SANE_Int,
114 SANE_Int* ) = 0;
115 void (*Sane::p_cancel)( SANE_Handle ) = 0;
116 SANE_Status (*Sane::p_set_io_mode)( SANE_Handle, SANE_Bool ) = 0;
117 SANE_Status (*Sane::p_get_select_fd)( SANE_Handle, SANE_Int* ) = 0;
118 SANE_String_Const (*Sane::p_strstatus)( SANE_Status ) = 0;
120 static BOOL bSaneSymbolLoadFailed = FALSE;
122 inline oslGenericFunction Sane::LoadSymbol( const char* pSymbolname )
124 oslGenericFunction pFunction = osl_getAsciiFunctionSymbol( pSaneLib, pSymbolname );
125 if( ! pFunction )
127 fprintf( stderr, "Could not load symbol %s\n",
128 pSymbolname );
129 bSaneSymbolLoadFailed = TRUE;
131 return pFunction;
134 SANE_Status Sane::ControlOption( int nOption, SANE_Action nAction,
135 void* pData )
137 SANE_Status nStatus = SANE_STATUS_GOOD;
138 SANE_Int nInfo = 0;
140 nStatus = p_control_option( maHandle, (SANE_Int)nOption,
141 nAction, pData, &nInfo );
142 DUMP_STATE( nStatus, "sane_control_option" );
143 #if OSL_DEBUG_LEVEL > 1
144 if( nStatus != SANE_STATUS_GOOD )
146 const char* pAction = "Unknown";
147 switch( nAction )
149 case SANE_ACTION_GET_VALUE:
150 pAction = "SANE_ACTION_GET_VALUE";break;
151 case SANE_ACTION_SET_VALUE:
152 pAction = "SANE_ACTION_SET_VALUE";break;
153 case SANE_ACTION_SET_AUTO:
154 pAction = "SANE_ACTION_SET_AUTO";break;
156 dbg_msg( "Option: \"%s\" action: %s\n",
157 ByteString( GetOptionName( nOption ), gsl_getSystemTextEncoding() ).GetBuffer(),
158 pAction );
160 #endif
161 // if( nInfo & ( SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS ) )
162 if( nInfo & SANE_INFO_RELOAD_OPTIONS )
163 ReloadOptions();
164 return nStatus;
167 Sane::Sane() :
168 mppOptions( 0 ),
169 mnOptions( 0 ),
170 mnDevice( -1 ),
171 maHandle( 0 )
173 if( ! nRefCount || ! pSaneLib )
174 Init();
175 nRefCount++;
178 Sane::~Sane()
180 if( IsOpen() )
181 Close();
182 nRefCount--;
183 if( ! nRefCount && pSaneLib )
184 DeInit();
187 void Sane::Init()
189 ::rtl::OUString sSaneLibName( ::rtl::OUString::createFromAscii( "libsane" SAL_DLLEXTENSION ) );
190 pSaneLib = osl_loadModule( sSaneLibName.pData, SAL_LOADMODULE_LAZY );
191 if( ! pSaneLib )
193 sSaneLibName = ::rtl::OUString::createFromAscii( "libsane" SAL_DLLEXTENSION ".1" );
194 pSaneLib = osl_loadModule( sSaneLibName.pData, SAL_LOADMODULE_LAZY );
196 // try reasonable places that might not be in the library search path
197 if( ! pSaneLib )
199 ::rtl::OUString sSaneLibSystemPath( ::rtl::OUString::createFromAscii( "/usr/local/lib/libsane" SAL_DLLEXTENSION ) );
200 osl_getFileURLFromSystemPath( sSaneLibSystemPath.pData, &sSaneLibName.pData );
201 pSaneLib = osl_loadModule( sSaneLibName.pData, SAL_LOADMODULE_LAZY );
204 if( pSaneLib )
206 bSaneSymbolLoadFailed = FALSE;
207 p_init = (SANE_Status(*)(SANE_Int*, SANE_Auth_Callback ))
208 LoadSymbol( "sane_init" );
209 p_exit = (void(*)())
210 LoadSymbol( "sane_exit" );
211 p_get_devices = (SANE_Status(*)(const SANE_Device***,
212 SANE_Bool ))
213 LoadSymbol( "sane_get_devices" );
214 p_open = (SANE_Status(*)(SANE_String_Const, SANE_Handle ))
215 LoadSymbol( "sane_open" );
216 p_close = (void(*)(SANE_Handle))
217 LoadSymbol( "sane_close" );
218 p_get_option_descriptor = (const SANE_Option_Descriptor*(*)(SANE_Handle,
219 SANE_Int))
220 LoadSymbol( "sane_get_option_descriptor" );
221 p_control_option = (SANE_Status(*)(SANE_Handle, SANE_Int,
222 SANE_Action, void*, SANE_Int*))
223 LoadSymbol( "sane_control_option" );
224 p_get_parameters = (SANE_Status(*)(SANE_Handle,SANE_Parameters*))
225 LoadSymbol( "sane_get_parameters" );
226 p_start = (SANE_Status(*)(SANE_Handle))
227 LoadSymbol( "sane_start" );
228 p_read = (SANE_Status(*)(SANE_Handle, SANE_Byte*,
229 SANE_Int, SANE_Int* ))
230 LoadSymbol( "sane_read" );
231 p_cancel = (void(*)(SANE_Handle))
232 LoadSymbol( "sane_cancel" );
233 p_set_io_mode = (SANE_Status(*)(SANE_Handle, SANE_Bool))
234 LoadSymbol( "sane_set_io_mode" );
235 p_get_select_fd = (SANE_Status(*)(SANE_Handle, SANE_Int*))
236 LoadSymbol( "sane_get_select_fd" );
237 p_strstatus = (SANE_String_Const(*)(SANE_Status))
238 LoadSymbol( "sane_strstatus" );
239 if( bSaneSymbolLoadFailed )
240 DeInit();
241 else
243 SANE_Status nStatus = p_init( &nVersion, 0 );
244 FAIL_SHUTDOWN_STATE( nStatus, "sane_init", );
245 nStatus = p_get_devices( (const SANE_Device***)&ppDevices,
246 SANE_FALSE );
247 FAIL_SHUTDOWN_STATE( nStatus, "sane_get_devices", );
248 for( nDevices = 0 ; ppDevices[ nDevices ]; nDevices++ ) ;
251 #if (OSL_DEBUG_LEVEL > 1) || defined DBG_UTIL
252 else
253 fprintf( stderr, "libsane%s could not be opened: %s\n", SAL_DLLEXTENSION,
254 dlerror() );
255 #endif
258 void Sane::DeInit()
260 if( pSaneLib )
262 p_exit();
263 osl_unloadModule( pSaneLib );
264 pSaneLib = 0;
268 void Sane::ReloadDevices()
270 if( IsOpen() )
271 Close();
272 DeInit();
273 Init();
276 void Sane::ReloadOptions()
278 if( ! IsOpen() )
279 return;
281 SANE_Option_Descriptor* pZero = (SANE_Option_Descriptor*)
282 p_get_option_descriptor( maHandle, 0 );
283 SANE_Word pOptions[2];
284 SANE_Status nStatus = p_control_option( maHandle, 0, SANE_ACTION_GET_VALUE,
285 (void*)pOptions, NULL );
286 if( nStatus != SANE_STATUS_GOOD )
287 fprintf( stderr, "Error: sane driver returned %s while reading number of options !\n", p_strstatus( nStatus ) );
289 mnOptions = pOptions[ 0 ];
290 if( (size_t)pZero->size > sizeof( SANE_Word ) )
291 fprintf( stderr, "driver returned numer of options with larger size tha SANE_Word !!!\n" );
292 if( mppOptions )
293 delete [] mppOptions;
294 mppOptions = (const SANE_Option_Descriptor**)new SANE_Option_Descriptor*[ mnOptions ];
295 mppOptions[ 0 ] = (SANE_Option_Descriptor*)pZero;
296 for( int i = 1; i < mnOptions; i++ )
297 mppOptions[ i ] = (SANE_Option_Descriptor*)
298 p_get_option_descriptor( maHandle, i );
300 CheckConsistency( NULL, TRUE );
302 maReloadOptionsLink.Call( this );
305 BOOL Sane::Open( const char* name )
307 int i;
309 SANE_Status nStatus = p_open( (SANE_String_Const)name, &maHandle );
310 FAIL_STATE( nStatus, "sane_open", FALSE );
312 ReloadOptions();
314 if( mnDevice == -1 )
316 ByteString aDevice( name );
317 for( i = 0; i < nDevices; i++ )
319 if( aDevice.Equals( ppDevices[i]->name ) )
321 mnDevice = i;
322 break;
327 return TRUE;
330 BOOL Sane::Open( int n )
332 if( n >= 0 && n < nDevices )
334 mnDevice = n;
335 return Open( (char*)ppDevices[n]->name );
337 return FALSE;
340 void Sane::Close()
342 if( maHandle )
344 p_close( maHandle );
345 delete [] mppOptions;
346 mppOptions = 0;
347 maHandle = 0;
348 mnDevice = -1;
352 int Sane::GetOptionByName( const char* rName )
354 int i;
355 ByteString aOption( rName );
356 for( i = 0; i < mnOptions; i++ )
358 if( mppOptions[i]->name && aOption.Equals( mppOptions[i]->name ) )
359 return i;
361 return -1;
364 BOOL Sane::GetOptionValue( int n, BOOL& rRet )
366 if( ! maHandle || mppOptions[n]->type != SANE_TYPE_BOOL )
367 return FALSE;
368 SANE_Word nRet;
369 SANE_Status nStatus = ControlOption( n, SANE_ACTION_GET_VALUE, &nRet );
370 if( nStatus != SANE_STATUS_GOOD )
371 return FALSE;
373 rRet = nRet;
374 return TRUE;
377 BOOL Sane::GetOptionValue( int n, ByteString& rRet )
379 BOOL bSuccess = FALSE;
380 if( ! maHandle || mppOptions[n]->type != SANE_TYPE_STRING )
381 return FALSE;
382 char* pRet = new char[mppOptions[n]->size+1];
383 SANE_Status nStatus = ControlOption( n, SANE_ACTION_GET_VALUE, pRet );
384 if( nStatus == SANE_STATUS_GOOD )
386 bSuccess = TRUE;
387 rRet = pRet;
389 delete [] pRet;
390 return bSuccess;
393 BOOL Sane::GetOptionValue( int n, double& rRet, int nElement )
395 BOOL bSuccess = FALSE;
397 if( ! maHandle || ( mppOptions[n]->type != SANE_TYPE_INT &&
398 mppOptions[n]->type != SANE_TYPE_FIXED ) )
399 return FALSE;
401 SANE_Word* pRet = new SANE_Word[mppOptions[n]->size/sizeof(SANE_Word)];
402 SANE_Status nStatus = ControlOption( n, SANE_ACTION_GET_VALUE, pRet );
403 if( nStatus == SANE_STATUS_GOOD )
405 bSuccess = TRUE;
406 if( mppOptions[n]->type == SANE_TYPE_INT )
407 rRet = (double)pRet[ nElement ];
408 else
409 rRet = SANE_UNFIX( pRet[nElement] );
411 delete [] pRet;
412 return bSuccess;
415 BOOL Sane::GetOptionValue( int n, double* pSet )
417 if( ! maHandle || ! ( mppOptions[n]->type == SANE_TYPE_FIXED ||
418 mppOptions[n]->type == SANE_TYPE_INT ) )
419 return FALSE;
421 SANE_Word* pFixedSet = new SANE_Word[mppOptions[n]->size/sizeof(SANE_Word)];
422 SANE_Status nStatus = ControlOption( n, SANE_ACTION_GET_VALUE, pFixedSet );
423 if( nStatus != SANE_STATUS_GOOD )
425 delete [] pFixedSet;
426 return FALSE;
428 for( size_t i = 0; i <mppOptions[n]->size/sizeof(SANE_Word); i++ )
430 if( mppOptions[n]->type == SANE_TYPE_FIXED )
431 pSet[i] = SANE_UNFIX( pFixedSet[i] );
432 else
433 pSet[i] = (double) pFixedSet[i];
435 delete [] pFixedSet;
436 return TRUE;
439 BOOL Sane::SetOptionValue( int n, BOOL bSet )
441 if( ! maHandle || mppOptions[n]->type != SANE_TYPE_BOOL )
442 return FALSE;
443 SANE_Word nRet = bSet ? SANE_TRUE : SANE_FALSE;
444 SANE_Status nStatus = ControlOption( n, SANE_ACTION_SET_VALUE, &nRet );
445 if( nStatus != SANE_STATUS_GOOD )
446 return FALSE;
447 return TRUE;
450 BOOL Sane::SetOptionValue( int n, const String& rSet )
452 if( ! maHandle || mppOptions[n]->type != SANE_TYPE_STRING )
453 return FALSE;
454 ByteString aSet( rSet, gsl_getSystemTextEncoding() );
455 SANE_Status nStatus = ControlOption( n, SANE_ACTION_SET_VALUE, (void*)aSet.GetBuffer() );
456 if( nStatus != SANE_STATUS_GOOD )
457 return FALSE;
458 return TRUE;
461 BOOL Sane::SetOptionValue( int n, double fSet, int nElement )
463 BOOL bSuccess = FALSE;
465 if( ! maHandle || ( mppOptions[n]->type != SANE_TYPE_INT &&
466 mppOptions[n]->type != SANE_TYPE_FIXED ) )
467 return FALSE;
469 SANE_Status nStatus;
470 if( mppOptions[n]->size/sizeof(SANE_Word) > 1 )
472 SANE_Word* pSet = new SANE_Word[mppOptions[n]->size/sizeof(SANE_Word)];
473 nStatus = ControlOption( n, SANE_ACTION_GET_VALUE, pSet );
474 if( nStatus == SANE_STATUS_GOOD )
476 pSet[nElement] = mppOptions[n]->type == SANE_TYPE_INT ?
477 (SANE_Word)fSet : SANE_FIX( fSet );
478 nStatus = ControlOption( n, SANE_ACTION_SET_VALUE, pSet );
480 delete [] pSet;
482 else
484 SANE_Word nSetTo =
485 mppOptions[n]->type == SANE_TYPE_INT ?
486 (SANE_Word)fSet : SANE_FIX( fSet );
488 nStatus = ControlOption( n, SANE_ACTION_SET_VALUE, &nSetTo );
489 if( nStatus == SANE_STATUS_GOOD )
490 bSuccess = TRUE;
492 return bSuccess;
495 BOOL Sane::SetOptionValue( int n, double* pSet )
497 if( ! maHandle || ( mppOptions[n]->type != SANE_TYPE_INT &&
498 mppOptions[n]->type != SANE_TYPE_FIXED ) )
499 return FALSE;
500 SANE_Word* pFixedSet = new SANE_Word[mppOptions[n]->size/sizeof(SANE_Word)];
501 for( size_t i = 0; i < mppOptions[n]->size/sizeof(SANE_Word); i++ )
503 if( mppOptions[n]->type == SANE_TYPE_FIXED )
504 pFixedSet[i] = SANE_FIX( pSet[i] );
505 else
506 pFixedSet[i] = (SANE_Word)pSet[i];
508 SANE_Status nStatus = ControlOption( n, SANE_ACTION_SET_VALUE, pFixedSet );
509 delete [] pFixedSet;
510 if( nStatus != SANE_STATUS_GOOD )
511 return FALSE;
512 return TRUE;
515 enum FrameStyleType {
516 FrameStyle_BW, FrameStyle_Gray, FrameStyle_RGB, FrameStyle_Separated
519 #define BYTE_BUFFER_SIZE 32768
521 static inline UINT8 _ReadValue( FILE* fp, int depth )
523 if( depth == 16 )
525 UINT16 nWord;
526 // data always come in native byte order !
527 // 16 bits is not really supported by backends as of now
528 // e.g. UMAX Astra 1200S delivers 16 bit but in BIGENDIAN
529 // against SANE documentation (xscanimage gets the same result
530 // as we do
531 fread( &nWord, 1, 2, fp );
532 return (UINT8)( nWord / 256 );
534 UINT8 nByte;
535 fread( &nByte, 1, 1, fp );
536 return nByte;
539 BOOL Sane::CheckConsistency( const char* pMes, BOOL bInit )
541 static SANE_Option_Descriptor** pDescArray = NULL;
542 static SANE_Option_Descriptor* pZero = NULL;
544 if( bInit )
546 pDescArray = (SANE_Option_Descriptor**)mppOptions;
547 if( mppOptions )
548 pZero = (SANE_Option_Descriptor*)mppOptions[0];
549 return TRUE;
552 BOOL bConsistent = TRUE;
554 if( pDescArray != mppOptions )
555 bConsistent = FALSE;
556 if( pZero != mppOptions[0] )
557 bConsistent = FALSE;
559 if( ! bConsistent )
560 dbg_msg( "Sane is not consistent. (%s)\n", pMes );
562 return bConsistent;
565 BOOL Sane::Start( BitmapTransporter& rBitmap )
567 int nStream = 0, nLine = 0, i = 0;
568 SANE_Parameters aParams;
569 FrameStyleType eType = FrameStyle_Gray;
570 BOOL bSuccess = TRUE;
571 BOOL bWidthSet = FALSE;
573 if( ! maHandle )
574 return FALSE;
576 int nWidthMM = 0;
577 int nHeightMM = 0;
578 double fTLx, fTLy, fBRx, fBRy, fResl = 0.0;
579 int nOption;
580 if( ( nOption = GetOptionByName( "tl-x" ) ) != -1 &&
581 GetOptionValue( nOption, fTLx, 0 ) &&
582 GetOptionUnit( nOption ) == SANE_UNIT_MM )
584 if( ( nOption = GetOptionByName( "br-x" ) ) != -1 &&
585 GetOptionValue( nOption, fBRx, 0 ) &&
586 GetOptionUnit( nOption ) == SANE_UNIT_MM )
588 nWidthMM = (int)fabs(fBRx - fTLx);
591 if( ( nOption = GetOptionByName( "tl-y" ) ) != -1 &&
592 GetOptionValue( nOption, fTLy, 0 ) &&
593 GetOptionUnit( nOption ) == SANE_UNIT_MM )
595 if( ( nOption = GetOptionByName( "br-y" ) ) != -1 &&
596 GetOptionValue( nOption, fBRy, 0 ) &&
597 GetOptionUnit( nOption ) == SANE_UNIT_MM )
599 nHeightMM = (int)fabs(fBRy - fTLy);
602 if( ( nOption = GetOptionByName( "resolution" ) ) != -1 )
603 GetOptionValue( nOption, fResl );
605 BYTE* pBuffer = NULL;
607 SANE_Status nStatus = SANE_STATUS_GOOD;
609 rBitmap.lock();
610 SvMemoryStream& aConverter = rBitmap.getStream();
611 aConverter.Seek( 0 );
612 aConverter.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
614 // write bitmap stream header
615 aConverter << 'B' << 'M';
616 aConverter << (sal_uInt32) 0;
617 aConverter << (sal_uInt32) 0;
618 aConverter << (sal_uInt32) 60;
620 // write BITMAPINFOHEADER
621 aConverter << (UINT32)40;
622 aConverter << (UINT32)0; // fill in width later
623 aConverter << (UINT32)0; // fill in height later
624 aConverter << (UINT16)1;
625 // create header for 24 bits
626 // correct later if necessary
627 aConverter << (UINT16)24;
628 aConverter << (UINT32)0;
629 aConverter << (UINT32)0;
630 aConverter << (UINT32)0;
631 aConverter << (UINT32)0;
632 aConverter << (UINT32)0;
633 aConverter << (UINT32)0;
635 for( nStream=0; nStream < 3 && bSuccess ; nStream++ )
637 nStatus = p_start( maHandle );
638 DUMP_STATE( nStatus, "sane_start" );
639 CheckConsistency( "sane_start" );
640 if( nStatus == SANE_STATUS_GOOD )
642 nStatus = p_get_parameters( maHandle, &aParams );
643 DUMP_STATE( nStatus, "sane_get_parameters" );
644 CheckConsistency( "sane_get_parameters" );
645 if (nStatus != SANE_STATUS_GOOD || aParams.bytes_per_line == 0)
647 bSuccess = FALSE;
648 break;
650 #if (OSL_DEBUG_LEVEL > 1) || defined DBG_UTIL
651 const char* ppFormats[] = { "SANE_FRAME_GRAY", "SANE_FRAME_RGB",
652 "SANE_FRAME_RED", "SANE_FRAME_GREEN",
653 "SANE_FRAME_BLUE", "Unknown !!!" };
654 fprintf( stderr, "Parameters for frame %d:\n", nStream );
655 if( aParams.format < 0 || aParams.format > 4 )
656 aParams.format = (SANE_Frame)5;
657 fprintf( stderr, "format: %s\n", ppFormats[ (int)aParams.format ] );
658 fprintf( stderr, "last_frame: %s\n", aParams.last_frame ? "TRUE" : "FALSE" );
659 fprintf( stderr, "depth: %d\n", (int)aParams.depth );
660 fprintf( stderr, "pixels_per_line: %d\n", (int)aParams.pixels_per_line );
661 fprintf( stderr, "bytes_per_line: %d\n", (int)aParams.bytes_per_line );
662 #endif
663 if( ! pBuffer )
665 pBuffer = new BYTE[ BYTE_BUFFER_SIZE < 4*aParams.bytes_per_line ? 4*aParams.bytes_per_line : BYTE_BUFFER_SIZE ];
668 if( aParams.last_frame )
669 nStream=3;
671 switch( aParams.format )
673 case SANE_FRAME_GRAY:
674 eType = FrameStyle_Gray;
675 if( aParams.depth == 1 )
676 eType = FrameStyle_BW;
677 break;
678 case SANE_FRAME_RGB:
679 eType = FrameStyle_RGB;
680 break;
681 case SANE_FRAME_RED:
682 case SANE_FRAME_GREEN:
683 case SANE_FRAME_BLUE:
684 eType = FrameStyle_Separated;
685 break;
686 default:
687 fprintf( stderr, "Warning: unknown frame style !!!\n" );
690 BOOL bSynchronousRead = TRUE;
692 // should be fail safe, but ... ??
693 nStatus = p_set_io_mode( maHandle, SANE_FALSE );
694 CheckConsistency( "sane_set_io_mode" );
695 if( nStatus != SANE_STATUS_GOOD )
697 bSynchronousRead = FALSE;
698 nStatus = p_set_io_mode( maHandle, SANE_TRUE );
699 CheckConsistency( "sane_set_io_mode" );
700 #if (OSL_DEBUG_LEVEL > 1) || defined DBG_UTIL
701 if( nStatus != SANE_STATUS_GOOD )
702 // what ?!?
703 fprintf( stderr, "Sane::Start: driver is confused\n" );
704 #endif
707 SANE_Int nLen=0;
708 SANE_Int fd = 0;
710 if( ! bSynchronousRead )
712 nStatus = p_get_select_fd( maHandle, &fd );
713 DUMP_STATE( nStatus, "sane_get_select_fd" );
714 CheckConsistency( "sane_get_select_fd" );
715 if( nStatus != SANE_STATUS_GOOD )
716 bSynchronousRead = TRUE;
718 FILE* pFrame = tmpfile();
719 if( ! pFrame )
721 bSuccess = FALSE;
722 break;
724 do {
725 if( ! bSynchronousRead )
727 fd_set fdset;
728 struct timeval tv;
730 FD_ZERO( &fdset );
731 FD_SET( (int)fd, &fdset );
732 tv.tv_sec = 5;
733 tv.tv_usec = 0;
734 if( select( fd+1, &fdset, NULL, NULL, &tv ) == 0 )
735 fprintf( stderr, "Timout on sane_read descriptor\n" );
737 nLen = 0;
738 nStatus = p_read( maHandle, pBuffer, BYTE_BUFFER_SIZE, &nLen );
739 CheckConsistency( "sane_read" );
740 if( nLen && ( nStatus == SANE_STATUS_GOOD ||
741 nStatus == SANE_STATUS_EOF ) )
743 fwrite( pBuffer, 1, nLen, pFrame );
745 else
746 DUMP_STATE( nStatus, "sane_read" );
747 } while( nStatus == SANE_STATUS_GOOD );
748 if( nStatus != SANE_STATUS_EOF )
750 fclose( pFrame );
751 bSuccess = FALSE;
752 break;
755 int nFrameLength = ftell( pFrame );
756 fseek( pFrame, 0, SEEK_SET );
757 UINT32 nWidth = (UINT32) aParams.pixels_per_line;
758 UINT32 nHeight = (UINT32) (nFrameLength / aParams.bytes_per_line);
759 if( ! bWidthSet )
761 if( ! fResl )
762 fResl = 300; // if all else fails that's a good guess
763 if( ! nWidthMM )
764 nWidthMM = (int)(((double)nWidth / fResl) * 25.4);
765 if( ! nHeightMM )
766 nHeightMM = (int)(((double)nHeight / fResl) * 25.4);
767 #if OSL_DEBUG_LEVEL > 1
768 fprintf( stderr, "set dimensions to (%d, %d) Pixel, (%d, %d) mm, resolution is %lg\n", (int)nWidth, (int)nHeight, (int)nWidthMM, (int)nHeightMM, fResl );
769 #endif
771 aConverter.Seek( 18 );
772 aConverter << (UINT32)nWidth;
773 aConverter << (UINT32)nHeight;
774 aConverter.Seek( 38 );
775 aConverter << (UINT32)(1000*nWidth/nWidthMM);
776 aConverter << (UINT32)(1000*nHeight/nHeightMM);
777 bWidthSet = TRUE;
779 aConverter.Seek(60);
781 if( eType == FrameStyle_BW )
783 aConverter.Seek( 10 );
784 aConverter << (sal_uInt32)64;
785 aConverter.Seek( 28 );
786 aConverter << (UINT16) 1;
787 aConverter.Seek( 54 );
788 // write color table
789 aConverter << (UINT16)0xffff;
790 aConverter << (UINT8)0xff;
791 aConverter << (UINT8)0;
792 aConverter << (UINT32)0;
793 aConverter.Seek( 64 );
795 else if( eType == FrameStyle_Gray )
797 aConverter.Seek( 10 );
798 aConverter << (sal_uInt32)1084;
799 aConverter.Seek( 28 );
800 aConverter << (UINT16) 8;
801 aConverter.Seek( 54 );
802 // write color table
803 for( nLine = 0; nLine < 256; nLine++ )
805 aConverter << (UINT8)nLine;
806 aConverter << (UINT8)nLine;
807 aConverter << (UINT8)nLine;
808 aConverter << (UINT8)0;
810 aConverter.Seek( 1084 );
813 for( nLine = nHeight-1;
814 nLine >= 0; nLine-- )
816 fseek( pFrame, nLine * aParams.bytes_per_line, SEEK_SET );
817 if( eType == FrameStyle_BW ||
818 ( eType == FrameStyle_Gray && aParams.depth == 8 )
821 fread( pBuffer, 1, aParams.bytes_per_line, pFrame );
822 aConverter.Write( pBuffer, aParams.bytes_per_line );
824 else if( eType == FrameStyle_Gray )
826 for( i = 0; i < (aParams.pixels_per_line); i++ )
828 UINT8 nGray = _ReadValue( pFrame, aParams.depth );
829 aConverter << nGray;
832 else if( eType == FrameStyle_RGB )
834 for( i = 0; i < (aParams.pixels_per_line); i++ )
836 UINT8 nRed, nGreen, nBlue;
837 nRed = _ReadValue( pFrame, aParams.depth );
838 nGreen = _ReadValue( pFrame, aParams.depth );
839 nBlue = _ReadValue( pFrame, aParams.depth );
840 aConverter << nBlue;
841 aConverter << nGreen;
842 aConverter << nRed;
845 else if( eType == FrameStyle_Separated )
847 for( i = 0; i < (aParams.pixels_per_line); i++ )
849 UINT8 nValue = _ReadValue( pFrame, aParams.depth );
850 switch( aParams.format )
852 case SANE_FRAME_RED:
853 aConverter.SeekRel( 2 );
854 aConverter << nValue;
855 break;
856 case SANE_FRAME_GREEN:
857 aConverter.SeekRel( 1 );
858 aConverter << nValue;
859 aConverter.SeekRel( 1 );
860 break;
861 case SANE_FRAME_BLUE:
862 aConverter << nValue;
863 aConverter.SeekRel( 2 );
864 break;
865 case SANE_FRAME_GRAY:
866 case SANE_FRAME_RGB:
867 break;
871 int nGap = aConverter.Tell() & 3;
872 if( nGap )
873 aConverter.SeekRel( 4-nGap );
875 fclose( pFrame ); // deletes tmpfile
876 if( eType != FrameStyle_Separated )
877 break;
879 else
880 bSuccess = FALSE;
882 // get stream length
883 aConverter.Seek( STREAM_SEEK_TO_END );
884 int nPos = aConverter.Tell();
886 aConverter.Seek( 2 );
887 aConverter << (sal_uInt32) nPos+1;
888 aConverter.Seek( 0 );
890 rBitmap.unlock();
892 if( bSuccess )
894 // only cancel a successful operation
895 // sane disrupts memory else
896 p_cancel( maHandle );
897 CheckConsistency( "sane_cancel" );
899 if( pBuffer )
900 delete [] pBuffer;
902 ReloadOptions();
905 dbg_msg( "Sane::Start returns with %s\n", bSuccess ? "TRUE" : "FALSE" );
907 return bSuccess;
910 int Sane::GetRange( int n, double*& rpDouble )
912 if( mppOptions[n]->constraint_type != SANE_CONSTRAINT_RANGE &&
913 mppOptions[n]->constraint_type != SANE_CONSTRAINT_WORD_LIST )
915 return -1;
918 rpDouble = 0;
919 int nItems, i;
920 BOOL bIsFixed = mppOptions[n]->type == SANE_TYPE_FIXED ? TRUE : FALSE;
922 dbg_msg( "Sane::GetRange of option %s ", mppOptions[n]->name );
923 if(mppOptions[n]->constraint_type == SANE_CONSTRAINT_RANGE )
925 double fMin, fMax, fQuant;
926 if( bIsFixed )
928 fMin = SANE_UNFIX( mppOptions[n]->constraint.range->min );
929 fMax = SANE_UNFIX( mppOptions[n]->constraint.range->max );
930 fQuant = SANE_UNFIX( mppOptions[n]->constraint.range->quant );
932 else
934 fMin = (double)mppOptions[n]->constraint.range->min;
935 fMax = (double)mppOptions[n]->constraint.range->max;
936 fQuant = (double)mppOptions[n]->constraint.range->quant;
938 if( fQuant != 0.0 )
940 dbg_msg( "quantum range [ %lg ; %lg ; %lg ]\n",
941 fMin, fQuant, fMax );
942 nItems = (int)((fMax - fMin)/fQuant)+1;
943 rpDouble = new double[ nItems ];
944 double fValue = fMin;
945 for( i = 0; i < nItems; i++, fValue += fQuant )
946 rpDouble[i] = fValue;
947 rpDouble[ nItems-1 ] = fMax;
948 return nItems;
950 else
952 dbg_msg( "normal range [ %lg %lg ]\n",
953 fMin, fMax );
954 rpDouble = new double[2];
955 rpDouble[0] = fMin;
956 rpDouble[1] = fMax;
957 return 0;
960 else
962 nItems = mppOptions[n]->constraint.word_list[0];
963 rpDouble = new double[nItems];
964 for( i=0; i<nItems; i++ )
966 rpDouble[i] = bIsFixed ?
967 SANE_UNFIX( mppOptions[n]->constraint.word_list[i+1] ) :
968 (double)mppOptions[n]->constraint.word_list[i+1];
970 dbg_msg( "wordlist [ %lg ... %lg ]\n",
971 rpDouble[ 0 ], rpDouble[ nItems-1 ] );
972 return nItems;
976 static const char *ppUnits[] = {
978 "[Pixel]",
979 "[Bit]",
980 "[mm]",
981 "[DPI]",
982 "[%]",
983 "[usec]"
986 String Sane::GetOptionUnitName( int n )
988 String aText;
989 SANE_Unit nUnit = mppOptions[n]->unit;
990 size_t nUnitAsSize = (size_t)nUnit;
991 if( nUnitAsSize > sizeof( ppUnits )/sizeof( ppUnits[0] ) )
992 aText = String::CreateFromAscii( "[unknown units]" );
993 else
994 aText = String( ppUnits[ nUnit ], gsl_getSystemTextEncoding() );
995 return aText;
998 BOOL Sane::ActivateButtonOption( int n )
1000 SANE_Status nStatus = ControlOption( n, SANE_ACTION_SET_VALUE, NULL );
1001 if( nStatus != SANE_STATUS_GOOD )
1002 return FALSE;
1003 return TRUE;