Update ooo320-m1
[ooovba.git] / extensions / source / scanner / sane.cxx
blobc88c7a456c800018783c15b2938c680a8da2f115
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: sane.cxx,v $
10 * $Revision: 1.16.60.2 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_extensions.hxx"
33 #include <cstdarg>
34 #include <math.h>
35 #include <osl/file.h>
36 #include <tools/stream.hxx>
37 #include <sane.hxx>
38 #include <dlfcn.h>
39 #include <stdio.h>
40 #include <unistd.h>
41 #include <sys/time.h>
42 #include <sys/types.h>
43 #include <sal/config.h>
45 #if (OSL_DEBUG_LEVEL > 1) || defined DBG_UTIL
46 #include <stdarg.h>
47 #define dump_state( a, b, c, d ) fprintf( stderr, a, b, c, d );
48 #else
49 #define dump_state( a, b, c, d ) ;
50 #endif
51 inline void dbg_msg( const char* pString, ... )
53 #if (OSL_DEBUG_LEVEL > 1) || defined DBG_UTIL
54 va_list ap;
55 va_start( ap, pString );
56 vfprintf( stderr, pString, ap );
57 va_end( ap );
58 #else
59 (void)pString;
60 #endif
63 #define FAIL_SHUTDOWN_STATE( x, y, z ) \
64 if( x != SANE_STATUS_GOOD ) \
65 { \
66 dump_state( "%s returned error %d (%s)\n", \
67 y, x, p_strstatus( x ) ); \
68 DeInit(); \
69 return z; \
72 #define FAIL_STATE( x, y, z ) \
73 if( x != SANE_STATUS_GOOD ) \
74 { \
75 dump_state( "%s returned error %d (%s)\n", \
76 y, x, p_strstatus( x ) ); \
77 return z; \
80 #define DUMP_STATE( x, y ) \
81 if( x != SANE_STATUS_GOOD ) \
82 { \
83 dump_state( "%s returned error %d (%s)\n", \
84 y, x, p_strstatus( x ) ); \
87 #define CHECK_STATE( x, y ) \
88 if( x != SANE_STATUS_GOOD ) \
89 { \
90 dump_state( "%s returned error %d (%s)\n", \
91 y, x, p_strstatus( x ) ); \
92 } \
93 else
95 int Sane::nRefCount = 0;
96 oslModule Sane::pSaneLib = 0;
97 SANE_Int Sane::nVersion = 0;
98 SANE_Device** Sane::ppDevices = 0;
99 int Sane::nDevices = 0;
101 SANE_Status (*Sane::p_init)( SANE_Int*,
102 SANE_Auth_Callback ) = 0;
103 void (*Sane::p_exit)() = 0;
104 SANE_Status (*Sane::p_get_devices)( const SANE_Device***,
105 SANE_Bool ) = 0;
106 SANE_Status (*Sane::p_open)( SANE_String_Const, SANE_Handle ) = 0;
107 void (*Sane::p_close)( SANE_Handle ) = 0;
108 const SANE_Option_Descriptor* (*Sane::p_get_option_descriptor)(
109 SANE_Handle, SANE_Int ) = 0;
110 SANE_Status (*Sane::p_control_option)( SANE_Handle, SANE_Int,
111 SANE_Action, void*,
112 SANE_Int* ) = 0;
113 SANE_Status (*Sane::p_get_parameters)( SANE_Handle,
114 SANE_Parameters* ) = 0;
115 SANE_Status (*Sane::p_start)( SANE_Handle ) = 0;
116 SANE_Status (*Sane::p_read)( SANE_Handle, SANE_Byte*, SANE_Int,
117 SANE_Int* ) = 0;
118 void (*Sane::p_cancel)( SANE_Handle ) = 0;
119 SANE_Status (*Sane::p_set_io_mode)( SANE_Handle, SANE_Bool ) = 0;
120 SANE_Status (*Sane::p_get_select_fd)( SANE_Handle, SANE_Int* ) = 0;
121 SANE_String_Const (*Sane::p_strstatus)( SANE_Status ) = 0;
123 static BOOL bSaneSymbolLoadFailed = FALSE;
125 inline oslGenericFunction Sane::LoadSymbol( const char* pSymbolname )
127 oslGenericFunction pFunction = osl_getAsciiFunctionSymbol( pSaneLib, pSymbolname );
128 if( ! pFunction )
130 fprintf( stderr, "Could not load symbol %s\n",
131 pSymbolname );
132 bSaneSymbolLoadFailed = TRUE;
134 return pFunction;
137 SANE_Status Sane::ControlOption( int nOption, SANE_Action nAction,
138 void* pData )
140 SANE_Status nStatus = SANE_STATUS_GOOD;
141 SANE_Int nInfo = 0;
143 nStatus = p_control_option( maHandle, (SANE_Int)nOption,
144 nAction, pData, &nInfo );
145 DUMP_STATE( nStatus, "sane_control_option" );
146 #if OSL_DEBUG_LEVEL > 1
147 if( nStatus != SANE_STATUS_GOOD )
149 const char* pAction = "Unknown";
150 switch( nAction )
152 case SANE_ACTION_GET_VALUE:
153 pAction = "SANE_ACTION_GET_VALUE";break;
154 case SANE_ACTION_SET_VALUE:
155 pAction = "SANE_ACTION_SET_VALUE";break;
156 case SANE_ACTION_SET_AUTO:
157 pAction = "SANE_ACTION_SET_AUTO";break;
159 dbg_msg( "Option: \"%s\" action: %s\n",
160 ByteString( GetOptionName( nOption ), gsl_getSystemTextEncoding() ).GetBuffer(),
161 pAction );
163 #endif
164 // if( nInfo & ( SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS ) )
165 if( nInfo & SANE_INFO_RELOAD_OPTIONS )
166 ReloadOptions();
167 return nStatus;
170 Sane::Sane() :
171 mppOptions( 0 ),
172 mnOptions( 0 ),
173 mnDevice( -1 ),
174 maHandle( 0 )
176 if( ! nRefCount || ! pSaneLib )
177 Init();
178 nRefCount++;
181 Sane::~Sane()
183 if( IsOpen() )
184 Close();
185 nRefCount--;
186 if( ! nRefCount && pSaneLib )
187 DeInit();
190 void Sane::Init()
192 ::rtl::OUString sSaneLibName( ::rtl::OUString::createFromAscii( "libsane" SAL_DLLEXTENSION ) );
193 pSaneLib = osl_loadModule( sSaneLibName.pData, SAL_LOADMODULE_LAZY );
194 if( ! pSaneLib )
196 sSaneLibName = ::rtl::OUString::createFromAscii( "libsane" SAL_DLLEXTENSION ".1" );
197 pSaneLib = osl_loadModule( sSaneLibName.pData, SAL_LOADMODULE_LAZY );
199 // try reasonable places that might not be in the library search path
200 if( ! pSaneLib )
202 ::rtl::OUString sSaneLibSystemPath( ::rtl::OUString::createFromAscii( "/usr/local/lib/libsane" SAL_DLLEXTENSION ) );
203 osl_getFileURLFromSystemPath( sSaneLibSystemPath.pData, &sSaneLibName.pData );
204 pSaneLib = osl_loadModule( sSaneLibName.pData, SAL_LOADMODULE_LAZY );
207 if( pSaneLib )
209 bSaneSymbolLoadFailed = FALSE;
210 p_init = (SANE_Status(*)(SANE_Int*, SANE_Auth_Callback ))
211 LoadSymbol( "sane_init" );
212 p_exit = (void(*)())
213 LoadSymbol( "sane_exit" );
214 p_get_devices = (SANE_Status(*)(const SANE_Device***,
215 SANE_Bool ))
216 LoadSymbol( "sane_get_devices" );
217 p_open = (SANE_Status(*)(SANE_String_Const, SANE_Handle ))
218 LoadSymbol( "sane_open" );
219 p_close = (void(*)(SANE_Handle))
220 LoadSymbol( "sane_close" );
221 p_get_option_descriptor = (const SANE_Option_Descriptor*(*)(SANE_Handle,
222 SANE_Int))
223 LoadSymbol( "sane_get_option_descriptor" );
224 p_control_option = (SANE_Status(*)(SANE_Handle, SANE_Int,
225 SANE_Action, void*, SANE_Int*))
226 LoadSymbol( "sane_control_option" );
227 p_get_parameters = (SANE_Status(*)(SANE_Handle,SANE_Parameters*))
228 LoadSymbol( "sane_get_parameters" );
229 p_start = (SANE_Status(*)(SANE_Handle))
230 LoadSymbol( "sane_start" );
231 p_read = (SANE_Status(*)(SANE_Handle, SANE_Byte*,
232 SANE_Int, SANE_Int* ))
233 LoadSymbol( "sane_read" );
234 p_cancel = (void(*)(SANE_Handle))
235 LoadSymbol( "sane_cancel" );
236 p_set_io_mode = (SANE_Status(*)(SANE_Handle, SANE_Bool))
237 LoadSymbol( "sane_set_io_mode" );
238 p_get_select_fd = (SANE_Status(*)(SANE_Handle, SANE_Int*))
239 LoadSymbol( "sane_get_select_fd" );
240 p_strstatus = (SANE_String_Const(*)(SANE_Status))
241 LoadSymbol( "sane_strstatus" );
242 if( bSaneSymbolLoadFailed )
243 DeInit();
244 else
246 SANE_Status nStatus = p_init( &nVersion, 0 );
247 FAIL_SHUTDOWN_STATE( nStatus, "sane_init", );
248 nStatus = p_get_devices( (const SANE_Device***)&ppDevices,
249 SANE_FALSE );
250 FAIL_SHUTDOWN_STATE( nStatus, "sane_get_devices", );
251 for( nDevices = 0 ; ppDevices[ nDevices ]; nDevices++ ) ;
254 #if (OSL_DEBUG_LEVEL > 1) || defined DBG_UTIL
255 else
256 fprintf( stderr, "libsane%s could not be opened: %s\n", SAL_DLLEXTENSION,
257 dlerror() );
258 #endif
261 void Sane::DeInit()
263 if( pSaneLib )
265 p_exit();
266 osl_unloadModule( pSaneLib );
267 pSaneLib = 0;
271 void Sane::ReloadDevices()
273 if( IsOpen() )
274 Close();
275 DeInit();
276 Init();
279 void Sane::ReloadOptions()
281 if( ! IsOpen() )
282 return;
284 SANE_Option_Descriptor* pZero = (SANE_Option_Descriptor*)
285 p_get_option_descriptor( maHandle, 0 );
286 SANE_Word pOptions[2];
287 SANE_Status nStatus = p_control_option( maHandle, 0, SANE_ACTION_GET_VALUE,
288 (void*)pOptions, NULL );
289 if( nStatus != SANE_STATUS_GOOD )
290 fprintf( stderr, "Error: sane driver returned %s while reading number of options !\n", p_strstatus( nStatus ) );
292 mnOptions = pOptions[ 0 ];
293 if( (size_t)pZero->size > sizeof( SANE_Word ) )
294 fprintf( stderr, "driver returned numer of options with larger size tha SANE_Word !!!\n" );
295 if( mppOptions )
296 delete [] mppOptions;
297 mppOptions = (const SANE_Option_Descriptor**)new SANE_Option_Descriptor*[ mnOptions ];
298 mppOptions[ 0 ] = (SANE_Option_Descriptor*)pZero;
299 for( int i = 1; i < mnOptions; i++ )
300 mppOptions[ i ] = (SANE_Option_Descriptor*)
301 p_get_option_descriptor( maHandle, i );
303 CheckConsistency( NULL, TRUE );
305 maReloadOptionsLink.Call( this );
308 BOOL Sane::Open( const char* name )
310 int i;
312 SANE_Status nStatus = p_open( (SANE_String_Const)name, &maHandle );
313 FAIL_STATE( nStatus, "sane_open", FALSE );
315 ReloadOptions();
317 if( mnDevice == -1 )
319 ByteString aDevice( name );
320 for( i = 0; i < nDevices; i++ )
322 if( aDevice.Equals( ppDevices[i]->name ) )
324 mnDevice = i;
325 break;
330 return TRUE;
333 BOOL Sane::Open( int n )
335 if( n >= 0 && n < nDevices )
337 mnDevice = n;
338 return Open( (char*)ppDevices[n]->name );
340 return FALSE;
343 void Sane::Close()
345 if( maHandle )
347 p_close( maHandle );
348 delete [] mppOptions;
349 mppOptions = 0;
350 maHandle = 0;
351 mnDevice = -1;
355 int Sane::GetOptionByName( const char* rName )
357 int i;
358 ByteString aOption( rName );
359 for( i = 0; i < mnOptions; i++ )
361 if( mppOptions[i]->name && aOption.Equals( mppOptions[i]->name ) )
362 return i;
364 return -1;
367 BOOL Sane::GetOptionValue( int n, BOOL& rRet )
369 if( ! maHandle || mppOptions[n]->type != SANE_TYPE_BOOL )
370 return FALSE;
371 SANE_Word nRet;
372 SANE_Status nStatus = ControlOption( n, SANE_ACTION_GET_VALUE, &nRet );
373 if( nStatus != SANE_STATUS_GOOD )
374 return FALSE;
376 rRet = nRet;
377 return TRUE;
380 BOOL Sane::GetOptionValue( int n, ByteString& rRet )
382 BOOL bSuccess = FALSE;
383 if( ! maHandle || mppOptions[n]->type != SANE_TYPE_STRING )
384 return FALSE;
385 char* pRet = new char[mppOptions[n]->size+1];
386 SANE_Status nStatus = ControlOption( n, SANE_ACTION_GET_VALUE, pRet );
387 if( nStatus == SANE_STATUS_GOOD )
389 bSuccess = TRUE;
390 rRet = pRet;
392 delete [] pRet;
393 return bSuccess;
396 BOOL Sane::GetOptionValue( int n, double& rRet, int nElement )
398 BOOL bSuccess = FALSE;
400 if( ! maHandle || ( mppOptions[n]->type != SANE_TYPE_INT &&
401 mppOptions[n]->type != SANE_TYPE_FIXED ) )
402 return FALSE;
404 SANE_Word* pRet = new SANE_Word[mppOptions[n]->size/sizeof(SANE_Word)];
405 SANE_Status nStatus = ControlOption( n, SANE_ACTION_GET_VALUE, pRet );
406 if( nStatus == SANE_STATUS_GOOD )
408 bSuccess = TRUE;
409 if( mppOptions[n]->type == SANE_TYPE_INT )
410 rRet = (double)pRet[ nElement ];
411 else
412 rRet = SANE_UNFIX( pRet[nElement] );
414 delete [] pRet;
415 return bSuccess;
418 BOOL Sane::GetOptionValue( int n, double* pSet )
420 if( ! maHandle || ! ( mppOptions[n]->type == SANE_TYPE_FIXED ||
421 mppOptions[n]->type == SANE_TYPE_INT ) )
422 return FALSE;
424 SANE_Word* pFixedSet = new SANE_Word[mppOptions[n]->size/sizeof(SANE_Word)];
425 SANE_Status nStatus = ControlOption( n, SANE_ACTION_GET_VALUE, pFixedSet );
426 if( nStatus != SANE_STATUS_GOOD )
428 delete [] pFixedSet;
429 return FALSE;
431 for( size_t i = 0; i <mppOptions[n]->size/sizeof(SANE_Word); i++ )
433 if( mppOptions[n]->type == SANE_TYPE_FIXED )
434 pSet[i] = SANE_UNFIX( pFixedSet[i] );
435 else
436 pSet[i] = (double) pFixedSet[i];
438 delete [] pFixedSet;
439 return TRUE;
442 BOOL Sane::SetOptionValue( int n, BOOL bSet )
444 if( ! maHandle || mppOptions[n]->type != SANE_TYPE_BOOL )
445 return FALSE;
446 SANE_Word nRet = bSet ? SANE_TRUE : SANE_FALSE;
447 SANE_Status nStatus = ControlOption( n, SANE_ACTION_SET_VALUE, &nRet );
448 if( nStatus != SANE_STATUS_GOOD )
449 return FALSE;
450 return TRUE;
453 BOOL Sane::SetOptionValue( int n, const String& rSet )
455 if( ! maHandle || mppOptions[n]->type != SANE_TYPE_STRING )
456 return FALSE;
457 ByteString aSet( rSet, gsl_getSystemTextEncoding() );
458 SANE_Status nStatus = ControlOption( n, SANE_ACTION_SET_VALUE, (void*)aSet.GetBuffer() );
459 if( nStatus != SANE_STATUS_GOOD )
460 return FALSE;
461 return TRUE;
464 BOOL Sane::SetOptionValue( int n, double fSet, int nElement )
466 BOOL bSuccess = FALSE;
468 if( ! maHandle || ( mppOptions[n]->type != SANE_TYPE_INT &&
469 mppOptions[n]->type != SANE_TYPE_FIXED ) )
470 return FALSE;
472 SANE_Status nStatus;
473 if( mppOptions[n]->size/sizeof(SANE_Word) > 1 )
475 SANE_Word* pSet = new SANE_Word[mppOptions[n]->size/sizeof(SANE_Word)];
476 nStatus = ControlOption( n, SANE_ACTION_GET_VALUE, pSet );
477 if( nStatus == SANE_STATUS_GOOD )
479 pSet[nElement] = mppOptions[n]->type == SANE_TYPE_INT ?
480 (SANE_Word)fSet : SANE_FIX( fSet );
481 nStatus = ControlOption( n, SANE_ACTION_SET_VALUE, pSet );
483 delete [] pSet;
485 else
487 SANE_Word nSetTo =
488 mppOptions[n]->type == SANE_TYPE_INT ?
489 (SANE_Word)fSet : SANE_FIX( fSet );
491 nStatus = ControlOption( n, SANE_ACTION_SET_VALUE, &nSetTo );
492 if( nStatus == SANE_STATUS_GOOD )
493 bSuccess = TRUE;
495 return bSuccess;
498 BOOL Sane::SetOptionValue( int n, double* pSet )
500 if( ! maHandle || ( mppOptions[n]->type != SANE_TYPE_INT &&
501 mppOptions[n]->type != SANE_TYPE_FIXED ) )
502 return FALSE;
503 SANE_Word* pFixedSet = new SANE_Word[mppOptions[n]->size/sizeof(SANE_Word)];
504 for( size_t i = 0; i < mppOptions[n]->size/sizeof(SANE_Word); i++ )
506 if( mppOptions[n]->type == SANE_TYPE_FIXED )
507 pFixedSet[i] = SANE_FIX( pSet[i] );
508 else
509 pFixedSet[i] = (SANE_Word)pSet[i];
511 SANE_Status nStatus = ControlOption( n, SANE_ACTION_SET_VALUE, pFixedSet );
512 delete [] pFixedSet;
513 if( nStatus != SANE_STATUS_GOOD )
514 return FALSE;
515 return TRUE;
518 enum FrameStyleType {
519 FrameStyle_BW, FrameStyle_Gray, FrameStyle_RGB, FrameStyle_Separated
522 #define BYTE_BUFFER_SIZE 32768
524 static inline UINT8 _ReadValue( FILE* fp, int depth )
526 if( depth == 16 )
528 UINT16 nWord;
529 // data always come in native byte order !
530 // 16 bits is not really supported by backends as of now
531 // e.g. UMAX Astra 1200S delivers 16 bit but in BIGENDIAN
532 // against SANE documentation (xscanimage gets the same result
533 // as we do
534 fread( &nWord, 1, 2, fp );
535 return (UINT8)( nWord / 256 );
537 UINT8 nByte;
538 fread( &nByte, 1, 1, fp );
539 return nByte;
542 BOOL Sane::CheckConsistency( const char* pMes, BOOL bInit )
544 static SANE_Option_Descriptor** pDescArray = NULL;
545 static SANE_Option_Descriptor* pZero = NULL;
547 if( bInit )
549 pDescArray = (SANE_Option_Descriptor**)mppOptions;
550 if( mppOptions )
551 pZero = (SANE_Option_Descriptor*)mppOptions[0];
552 return TRUE;
555 BOOL bConsistent = TRUE;
557 if( pDescArray != mppOptions )
558 bConsistent = FALSE;
559 if( pZero != mppOptions[0] )
560 bConsistent = FALSE;
562 if( ! bConsistent )
563 dbg_msg( "Sane is not consistent. (%s)\n", pMes );
565 return bConsistent;
568 BOOL Sane::Start( BitmapTransporter& rBitmap )
570 int nStream = 0, nLine = 0, i = 0;
571 SANE_Parameters aParams;
572 FrameStyleType eType = FrameStyle_Gray;
573 BOOL bSuccess = TRUE;
574 BOOL bWidthSet = FALSE;
576 if( ! maHandle )
577 return FALSE;
579 int nWidthMM = 0;
580 int nHeightMM = 0;
581 double fTLx, fTLy, fBRx, fBRy, fResl = 0.0;
582 int nOption;
583 if( ( nOption = GetOptionByName( "tl-x" ) ) != -1 &&
584 GetOptionValue( nOption, fTLx, 0 ) &&
585 GetOptionUnit( nOption ) == SANE_UNIT_MM )
587 if( ( nOption = GetOptionByName( "br-x" ) ) != -1 &&
588 GetOptionValue( nOption, fBRx, 0 ) &&
589 GetOptionUnit( nOption ) == SANE_UNIT_MM )
591 nWidthMM = (int)fabs(fBRx - fTLx);
594 if( ( nOption = GetOptionByName( "tl-y" ) ) != -1 &&
595 GetOptionValue( nOption, fTLy, 0 ) &&
596 GetOptionUnit( nOption ) == SANE_UNIT_MM )
598 if( ( nOption = GetOptionByName( "br-y" ) ) != -1 &&
599 GetOptionValue( nOption, fBRy, 0 ) &&
600 GetOptionUnit( nOption ) == SANE_UNIT_MM )
602 nHeightMM = (int)fabs(fBRy - fTLy);
605 if( ( nOption = GetOptionByName( "resolution" ) ) != -1 )
606 GetOptionValue( nOption, fResl );
608 BYTE* pBuffer = NULL;
610 SANE_Status nStatus = SANE_STATUS_GOOD;
612 rBitmap.lock();
613 SvMemoryStream& aConverter = rBitmap.getStream();
614 aConverter.Seek( 0 );
615 aConverter.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
617 // write bitmap stream header
618 aConverter << 'B' << 'M';
619 aConverter << (sal_uInt32) 0;
620 aConverter << (sal_uInt32) 0;
621 aConverter << (sal_uInt32) 60;
623 // write BITMAPINFOHEADER
624 aConverter << (UINT32)40;
625 aConverter << (UINT32)0; // fill in width later
626 aConverter << (UINT32)0; // fill in height later
627 aConverter << (UINT16)1;
628 // create header for 24 bits
629 // correct later if necessary
630 aConverter << (UINT16)24;
631 aConverter << (UINT32)0;
632 aConverter << (UINT32)0;
633 aConverter << (UINT32)0;
634 aConverter << (UINT32)0;
635 aConverter << (UINT32)0;
636 aConverter << (UINT32)0;
638 for( nStream=0; nStream < 3 && bSuccess ; nStream++ )
640 nStatus = p_start( maHandle );
641 DUMP_STATE( nStatus, "sane_start" );
642 CheckConsistency( "sane_start" );
643 if( nStatus == SANE_STATUS_GOOD )
645 nStatus = p_get_parameters( maHandle, &aParams );
646 DUMP_STATE( nStatus, "sane_get_parameters" );
647 CheckConsistency( "sane_get_parameters" );
648 #if (OSL_DEBUG_LEVEL > 1) || defined DBG_UTIL
649 const char* ppFormats[] = { "SANE_FRAME_GRAY", "SANE_FRAME_RGB",
650 "SANE_FRAME_RED", "SANE_FRAME_GREEN",
651 "SANE_FRAME_BLUE", "Unknown !!!" };
652 fprintf( stderr, "Parameters for frame %d:\n", nStream );
653 if( aParams.format < 0 || aParams.format > 4 )
654 aParams.format = (SANE_Frame)5;
655 fprintf( stderr, "format: %s\n", ppFormats[ (int)aParams.format ] );
656 fprintf( stderr, "last_frame: %s\n", aParams.last_frame ? "TRUE" : "FALSE" );
657 fprintf( stderr, "depth: %d\n", (int)aParams.depth );
658 fprintf( stderr, "pixels_per_line: %d\n", (int)aParams.pixels_per_line );
659 fprintf( stderr, "bytes_per_line: %d\n", (int)aParams.bytes_per_line );
660 #endif
661 if( ! pBuffer )
663 pBuffer = new BYTE[ BYTE_BUFFER_SIZE < 4*aParams.bytes_per_line ? 4*aParams.bytes_per_line : BYTE_BUFFER_SIZE ];
666 if( aParams.last_frame )
667 nStream=3;
669 switch( aParams.format )
671 case SANE_FRAME_GRAY:
672 eType = FrameStyle_Gray;
673 if( aParams.depth == 1 )
674 eType = FrameStyle_BW;
675 break;
676 case SANE_FRAME_RGB:
677 eType = FrameStyle_RGB;
678 break;
679 case SANE_FRAME_RED:
680 case SANE_FRAME_GREEN:
681 case SANE_FRAME_BLUE:
682 eType = FrameStyle_Separated;
683 break;
684 default:
685 fprintf( stderr, "Warning: unknown frame style !!!\n" );
688 BOOL bSynchronousRead = TRUE;
690 // should be fail safe, but ... ??
691 nStatus = p_set_io_mode( maHandle, SANE_FALSE );
692 CheckConsistency( "sane_set_io_mode" );
693 if( nStatus != SANE_STATUS_GOOD )
695 bSynchronousRead = FALSE;
696 nStatus = p_set_io_mode( maHandle, SANE_TRUE );
697 CheckConsistency( "sane_set_io_mode" );
698 #if (OSL_DEBUG_LEVEL > 1) || defined DBG_UTIL
699 if( nStatus != SANE_STATUS_GOOD )
700 // what ?!?
701 fprintf( stderr, "Sane::Start: driver is confused\n" );
702 #endif
705 SANE_Int nLen=0;
706 SANE_Int fd = 0;
708 if( ! bSynchronousRead )
710 nStatus = p_get_select_fd( maHandle, &fd );
711 DUMP_STATE( nStatus, "sane_get_select_fd" );
712 CheckConsistency( "sane_get_select_fd" );
713 if( nStatus != SANE_STATUS_GOOD )
714 bSynchronousRead = TRUE;
716 FILE* pFrame = tmpfile();
717 if( ! pFrame )
719 bSuccess = FALSE;
720 break;
722 do {
723 if( ! bSynchronousRead )
725 fd_set fdset;
726 struct timeval tv;
728 FD_ZERO( &fdset );
729 FD_SET( (int)fd, &fdset );
730 tv.tv_sec = 5;
731 tv.tv_usec = 0;
732 if( select( fd+1, &fdset, NULL, NULL, &tv ) == 0 )
733 fprintf( stderr, "Timout on sane_read descriptor\n" );
735 nLen = 0;
736 nStatus = p_read( maHandle, pBuffer, BYTE_BUFFER_SIZE, &nLen );
737 CheckConsistency( "sane_read" );
738 if( nLen && ( nStatus == SANE_STATUS_GOOD ||
739 nStatus == SANE_STATUS_EOF ) )
741 fwrite( pBuffer, 1, nLen, pFrame );
743 else
744 DUMP_STATE( nStatus, "sane_read" );
745 } while( nStatus == SANE_STATUS_GOOD );
746 if( nStatus != SANE_STATUS_EOF )
748 fclose( pFrame );
749 bSuccess = FALSE;
750 break;
753 int nFrameLength = ftell( pFrame );
754 fseek( pFrame, 0, SEEK_SET );
755 UINT32 nWidth = (UINT32) aParams.pixels_per_line;
756 UINT32 nHeight = (UINT32) (nFrameLength / aParams.bytes_per_line);
757 if( ! bWidthSet )
759 if( ! fResl )
760 fResl = 300; // if all else fails that's a good guess
761 if( ! nWidthMM )
762 nWidthMM = (int)(((double)nWidth / fResl) * 25.4);
763 if( ! nHeightMM )
764 nHeightMM = (int)(((double)nHeight / fResl) * 25.4);
765 #if OSL_DEBUG_LEVEL > 1
766 fprintf( stderr, "set dimensions to (%d, %d) Pixel, (%d, %d) mm, resolution is %lg\n", (int)nWidth, (int)nHeight, (int)nWidthMM, (int)nHeightMM, fResl );
767 #endif
769 aConverter.Seek( 18 );
770 aConverter << (UINT32)nWidth;
771 aConverter << (UINT32)nHeight;
772 aConverter.Seek( 38 );
773 aConverter << (UINT32)(1000*nWidth/nWidthMM);
774 aConverter << (UINT32)(1000*nHeight/nHeightMM);
775 bWidthSet = TRUE;
777 aConverter.Seek(60);
779 if( eType == FrameStyle_BW )
781 aConverter.Seek( 10 );
782 aConverter << (sal_uInt32)64;
783 aConverter.Seek( 28 );
784 aConverter << (UINT16) 1;
785 aConverter.Seek( 54 );
786 // write color table
787 aConverter << (UINT16)0xffff;
788 aConverter << (UINT8)0xff;
789 aConverter << (UINT8)0;
790 aConverter << (UINT32)0;
791 aConverter.Seek( 64 );
793 else if( eType == FrameStyle_Gray )
795 aConverter.Seek( 10 );
796 aConverter << (sal_uInt32)1084;
797 aConverter.Seek( 28 );
798 aConverter << (UINT16) 8;
799 aConverter.Seek( 54 );
800 // write color table
801 for( nLine = 0; nLine < 256; nLine++ )
803 aConverter << (UINT8)nLine;
804 aConverter << (UINT8)nLine;
805 aConverter << (UINT8)nLine;
806 aConverter << (UINT8)0;
808 aConverter.Seek( 1084 );
811 for( nLine = nHeight-1;
812 nLine >= 0; nLine-- )
814 fseek( pFrame, nLine * aParams.bytes_per_line, SEEK_SET );
815 if( eType == FrameStyle_BW ||
816 ( eType == FrameStyle_Gray && aParams.depth == 8 )
819 fread( pBuffer, 1, aParams.bytes_per_line, pFrame );
820 aConverter.Write( pBuffer, aParams.bytes_per_line );
822 else if( eType == FrameStyle_Gray )
824 for( i = 0; i < (aParams.pixels_per_line); i++ )
826 UINT8 nGray = _ReadValue( pFrame, aParams.depth );
827 aConverter << nGray;
830 else if( eType == FrameStyle_RGB )
832 for( i = 0; i < (aParams.pixels_per_line); i++ )
834 UINT8 nRed, nGreen, nBlue;
835 nRed = _ReadValue( pFrame, aParams.depth );
836 nGreen = _ReadValue( pFrame, aParams.depth );
837 nBlue = _ReadValue( pFrame, aParams.depth );
838 aConverter << nBlue;
839 aConverter << nGreen;
840 aConverter << nRed;
843 else if( eType == FrameStyle_Separated )
845 for( i = 0; i < (aParams.pixels_per_line); i++ )
847 UINT8 nValue = _ReadValue( pFrame, aParams.depth );
848 switch( aParams.format )
850 case SANE_FRAME_RED:
851 aConverter.SeekRel( 2 );
852 aConverter << nValue;
853 break;
854 case SANE_FRAME_GREEN:
855 aConverter.SeekRel( 1 );
856 aConverter << nValue;
857 aConverter.SeekRel( 1 );
858 break;
859 case SANE_FRAME_BLUE:
860 aConverter << nValue;
861 aConverter.SeekRel( 2 );
862 break;
863 case SANE_FRAME_GRAY:
864 case SANE_FRAME_RGB:
865 break;
869 int nGap = aConverter.Tell() & 3;
870 if( nGap )
871 aConverter.SeekRel( 4-nGap );
873 fclose( pFrame ); // deletes tmpfile
874 if( eType != FrameStyle_Separated )
875 break;
877 else
878 bSuccess = FALSE;
880 // get stream length
881 aConverter.Seek( STREAM_SEEK_TO_END );
882 int nPos = aConverter.Tell();
884 aConverter.Seek( 2 );
885 aConverter << (sal_uInt32) nPos+1;
886 aConverter.Seek( 0 );
888 rBitmap.unlock();
890 if( bSuccess )
892 // only cancel a successful operation
893 // sane disrupts memory else
894 p_cancel( maHandle );
895 CheckConsistency( "sane_cancel" );
897 if( pBuffer )
898 delete [] pBuffer;
900 ReloadOptions();
903 dbg_msg( "Sane::Start returns with %s\n", bSuccess ? "TRUE" : "FALSE" );
905 return bSuccess;
908 int Sane::GetRange( int n, double*& rpDouble )
910 if( mppOptions[n]->constraint_type != SANE_CONSTRAINT_RANGE &&
911 mppOptions[n]->constraint_type != SANE_CONSTRAINT_WORD_LIST )
913 return -1;
916 rpDouble = 0;
917 int nItems, i;
918 BOOL bIsFixed = mppOptions[n]->type == SANE_TYPE_FIXED ? TRUE : FALSE;
920 dbg_msg( "Sane::GetRange of option %s ", mppOptions[n]->name );
921 if(mppOptions[n]->constraint_type == SANE_CONSTRAINT_RANGE )
923 double fMin, fMax, fQuant;
924 if( bIsFixed )
926 fMin = SANE_UNFIX( mppOptions[n]->constraint.range->min );
927 fMax = SANE_UNFIX( mppOptions[n]->constraint.range->max );
928 fQuant = SANE_UNFIX( mppOptions[n]->constraint.range->quant );
930 else
932 fMin = (double)mppOptions[n]->constraint.range->min;
933 fMax = (double)mppOptions[n]->constraint.range->max;
934 fQuant = (double)mppOptions[n]->constraint.range->quant;
936 if( fQuant != 0.0 )
938 dbg_msg( "quantum range [ %lg ; %lg ; %lg ]\n",
939 fMin, fQuant, fMax );
940 nItems = (int)((fMax - fMin)/fQuant)+1;
941 rpDouble = new double[ nItems ];
942 double fValue = fMin;
943 for( i = 0; i < nItems; i++, fValue += fQuant )
944 rpDouble[i] = fValue;
945 rpDouble[ nItems-1 ] = fMax;
946 return nItems;
948 else
950 dbg_msg( "normal range [ %lg %lg ]\n",
951 fMin, fMax );
952 rpDouble = new double[2];
953 rpDouble[0] = fMin;
954 rpDouble[1] = fMax;
955 return 0;
958 else
960 nItems = mppOptions[n]->constraint.word_list[0];
961 rpDouble = new double[nItems];
962 for( i=0; i<nItems; i++ )
964 rpDouble[i] = bIsFixed ?
965 SANE_UNFIX( mppOptions[n]->constraint.word_list[i+1] ) :
966 (double)mppOptions[n]->constraint.word_list[i+1];
968 dbg_msg( "wordlist [ %lg ... %lg ]\n",
969 rpDouble[ 0 ], rpDouble[ nItems-1 ] );
970 return nItems;
974 static const char *ppUnits[] = {
976 "[Pixel]",
977 "[Bit]",
978 "[mm]",
979 "[DPI]",
980 "[%]",
981 "[usec]"
984 String Sane::GetOptionUnitName( int n )
986 String aText;
987 SANE_Unit nUnit = mppOptions[n]->unit;
988 size_t nUnitAsSize = (size_t)nUnit;
989 if( nUnitAsSize > sizeof( ppUnits )/sizeof( ppUnits[0] ) )
990 aText = String::CreateFromAscii( "[unknown units]" );
991 else
992 aText = String( ppUnits[ nUnit ], gsl_getSystemTextEncoding() );
993 return aText;
996 BOOL Sane::ActivateButtonOption( int n )
998 SANE_Status nStatus = ControlOption( n, SANE_ACTION_SET_VALUE, NULL );
999 if( nStatus != SANE_STATUS_GOOD )
1000 return FALSE;
1001 return TRUE;