2023-10-08 07:26:18 +00:00
# include "scanned_img.h"
2022-06-15 03:04:40 +00:00
# include <Windows.h>
2022-06-16 08:04:58 +00:00
# include <Shlwapi.h>
# pragma comment(lib, "Shlwapi.lib")
2022-06-15 03:04:40 +00:00
2022-06-16 08:04:58 +00:00
# include "../../code_device/hgsane/sane_hg_mdw.h"
2023-02-07 08:55:51 +00:00
# include "../../sdk/include/lang/app_language.h"
2022-06-15 03:04:40 +00:00
2022-06-16 08:04:58 +00:00
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
namespace local_trans
{
std : : string u2a ( const wchar_t * u , UINT cp )
{
std : : string a ( " " ) ;
if ( u )
{
char * ansi = NULL ;
int len = 0 ;
len = WideCharToMultiByte ( cp , 0 , u , lstrlenW ( u ) , NULL , 0 , NULL , NULL ) ;
ansi = new char [ len + 2 ] ;
len = WideCharToMultiByte ( cp , 0 , u , lstrlenW ( u ) , ansi , len , NULL , NULL ) ;
ansi [ len - - ] = 0 ;
a = ansi ;
delete [ ] ansi ;
}
2023-02-07 08:55:51 +00:00
return std : : move ( a ) ;
2022-06-16 08:04:58 +00:00
}
std : : wstring a2u ( const char * asc , UINT cp )
{
std : : wstring u ( L " " ) ;
if ( asc )
{
wchar_t * buf = NULL ;
int len = 0 ;
len = MultiByteToWideChar ( cp , 0 , asc , lstrlenA ( asc ) , NULL , 0 ) ;
buf = new wchar_t [ len + 2 ] ;
len = MultiByteToWideChar ( cp , 0 , asc , lstrlenA ( asc ) , buf , len ) ;
buf [ len - - ] = 0 ;
u = buf ;
delete [ ] buf ;
}
2023-02-07 08:55:51 +00:00
return std : : move ( u ) ;
}
std : : wstring lang_trans_between_hz936 ( const wchar_t * in , bool from_hz )
{
std : : string a ( u2a ( in , CP_UTF8 ) ) ;
if ( from_hz )
a = from_default_language ( a . c_str ( ) , nullptr ) ;
else
a = to_default_language ( a . c_str ( ) , nullptr ) ;
return std : : move ( a2u ( a . c_str ( ) , CP_UTF8 ) ) ;
}
const char * __stdcall lang_trans_between_hz936 ( const char * in , bool from_hz , void * param )
{
return from_hz ? from_default_language ( in , nullptr ) : to_default_language ( in , nullptr ) ;
2022-06-16 08:04:58 +00:00
}
}
2022-06-15 03:04:40 +00:00
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// class refer
refer : : refer ( ) : ref_ ( 1 )
{ }
refer : : ~ refer ( )
{ }
COM_API_IMPLEMENT ( refer , long , add_ref ( void ) )
{
return InterlockedIncrement ( & ref_ ) ;
}
COM_API_IMPLEMENT ( refer , long , release ( void ) )
{
long ref = InterlockedDecrement ( & ref_ ) ;
if ( ref = = 0 )
delete this ;
return ref ;
}
2022-06-16 08:04:58 +00:00
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// class mapping_buf
const unsigned int max_mem_block = 2 * 1024 * 1024 ;
2022-09-20 04:41:32 +00:00
extern void __stdcall log_info ( const wchar_t * info , int level ) ;
2022-06-16 08:04:58 +00:00
mapping_buf : : mapping_buf ( ) : bytes_ ( 0 ) , offset_ ( 0 ) , mapped_bytes_ ( 0 ) , map_ ( NULL ) , buf_ ( NULL ) , file_ ( " " ) , rmv_file_ ( true ) , page_size_ ( 0 ) , is_mem_ ( false )
{
SYSTEM_INFO si = { 0 } ;
GetSystemInfo ( & si ) ;
page_size_ = si . dwPageSize ;
map_unit_ = si . dwAllocationGranularity ;
}
mapping_buf : : ~ mapping_buf ( )
{
close ( ) ;
}
void mapping_buf : : init_map ( const char * file , unsigned long long size )
{
HANDLE f = INVALID_HANDLE_VALUE ;
if ( size )
{
f = CreateFileA ( file , GENERIC_READ | GENERIC_WRITE , FILE_SHARE_READ , NULL , CREATE_ALWAYS , FILE_ATTRIBUTE_NORMAL , NULL ) ;
if ( f ! = INVALID_HANDLE_VALUE )
{
unsigned long long total = size - 1 ;
LONG * p32 = ( LONG * ) & total ;
* p32 = SetFilePointer ( f , * p32 , p32 + 1 , FILE_BEGIN ) ;
total + + ;
if ( total = = size )
{
DWORD wrote = 1 ;
WriteFile ( f , " \0 " , 1 , & wrote , NULL ) ;
map_ = CreateFileMapping ( f , NULL , PAGE_READWRITE , p32 [ 1 ] , p32 [ 0 ] , NULL ) ;
}
CloseHandle ( f ) ;
if ( ! map_ )
DeleteFileA ( file ) ;
}
2022-09-20 04:41:32 +00:00
{
std : : wstring info ( local_trans : : a2u ( file ) ) ;
wchar_t buf [ 80 ] = { 0 } ;
swprintf_s ( buf , _countof ( buf ) - 1 , L " Mapping %u bytes to file: " , size ) ;
2023-05-20 04:02:26 +00:00
log_info ( ( buf + info + L " \r \n " ) . c_str ( ) , 1 ) ;
2022-09-20 04:41:32 +00:00
}
2022-06-16 08:04:58 +00:00
}
else
{
f = CreateFileA ( file , GENERIC_READ | GENERIC_WRITE , FILE_SHARE_READ , NULL , OPEN_EXISTING , FILE_ATTRIBUTE_NORMAL , NULL ) ;
if ( f ! = INVALID_HANDLE_VALUE )
{
DWORD * p32 = ( DWORD * ) & size ;
* p32 = GetFileSize ( f , p32 + 1 ) ;
map_ = CreateFileMapping ( f , NULL , PAGE_READWRITE , p32 [ 1 ] , p32 [ 0 ] , NULL ) ;
CloseHandle ( f ) ;
}
}
if ( map_ )
{
bytes_ = size ;
file_ = file ;
buffer ( 0 , NULL ) ;
if ( ! map_ )
close ( ) ;
}
}
void mapping_buf : : close ( void )
{
if ( buf_ )
{
if ( is_mem_ )
delete [ ] buf_ ;
else
UnmapViewOfFile ( buf_ ) ;
}
buf_ = NULL ;
if ( map_ )
CloseHandle ( map_ ) ;
map_ = NULL ;
if ( rmv_file_ & & file_ . length ( ) )
DeleteFileA ( file_ . c_str ( ) ) ;
file_ = " " ;
bytes_ = offset_ = 0 ;
mapped_bytes_ = 0 ;
rmv_file_ = true ;
is_mem_ = false ;
}
void mapping_buf : : map ( void )
{
DWORD * off = ( DWORD * ) & offset_ ;
buf_ = ( unsigned char * ) MapViewOfFile ( map_ , FILE_MAP_READ | FILE_MAP_WRITE , off [ 1 ] , off [ 0 ] , mapped_bytes_ ) ;
if ( ! buf_ )
{
DWORD err = GetLastError ( ) ;
mapped_bytes_ / = map_unit_ ;
mapped_bytes_ * = map_unit_ ;
while ( mapped_bytes_ > map_unit_ )
{
buf_ = ( unsigned char * ) MapViewOfFile ( map_ , FILE_MAP_READ | FILE_MAP_WRITE , off [ 1 ] , off [ 0 ] , mapped_bytes_ ) ;
if ( buf_ )
break ;
mapped_bytes_ / = 2 ;
}
if ( ! buf_ )
mapped_bytes_ = 0 ;
}
}
void mapping_buf : : set_buffer ( unsigned char * & buf , unsigned long long off , unsigned int * bytes )
{
buf = buf_ + ( off - offset_ ) ;
if ( bytes )
2022-07-18 02:55:01 +00:00
* bytes = mapped_bytes_ - ( unsigned int ) ( off - offset_ ) ;
2022-06-16 08:04:58 +00:00
}
2022-06-29 08:13:05 +00:00
unsigned char * mapping_buf : : allocate ( const wchar_t * file , unsigned long long size , bool force_file )
2022-06-16 08:04:58 +00:00
{
close ( ) ;
std : : string ansi ( local_trans : : u2a ( file ) ) ;
2022-06-29 08:13:05 +00:00
if ( force_file | | size > = 100 * 1024 * 1024 | | PathFileExistsW ( file ) )
2022-06-16 08:04:58 +00:00
{
init_map ( ansi . c_str ( ) , size ) ;
}
else
{
try
{
2022-07-18 02:55:01 +00:00
buf_ = new unsigned char [ ( unsigned int ) size ] ;
2022-06-16 08:04:58 +00:00
is_mem_ = true ;
2022-07-18 02:55:01 +00:00
bytes_ = size ;
mapped_bytes_ = ( unsigned int ) size ;
2022-06-16 08:04:58 +00:00
}
catch ( . . . )
{
is_mem_ = false ;
init_map ( ansi . c_str ( ) , size ) ;
}
}
return buf_ ;
}
unsigned char * mapping_buf : : buffer ( unsigned long long off , unsigned int * bytes )
{
unsigned int size = bytes ? * bytes : 1 * 1024 * 1024 * 1024 ;
unsigned char * buf = NULL ;
if ( size > bytes_ - offset_ )
2022-07-18 02:55:01 +00:00
size = ( unsigned int ) ( bytes_ - offset_ ) ;
2022-06-16 08:04:58 +00:00
if ( buf_ & & off > = offset_ & & size + ( off - offset_ ) < = mapped_bytes_ )
{
set_buffer ( buf , off , bytes ) ;
}
else if ( ! is_mem_ )
{
if ( off < bytes_ )
{
if ( buf_ )
UnmapViewOfFile ( buf_ ) ;
offset_ = off / map_unit_ * map_unit_ ;
2022-07-18 02:55:01 +00:00
mapped_bytes_ = ( unsigned int ) ( bytes_ - offset_ ) ;
2022-06-16 08:04:58 +00:00
map ( ) ;
if ( buf_ )
set_buffer ( buf , off , bytes ) ;
}
}
return buf ;
}
bool mapping_buf : : save ( const void * data , size_t * bytes , unsigned long long off )
{
unsigned int len = * bytes , total = 0 ;
2022-06-18 00:54:01 +00:00
unsigned char * buf = buffer ( off , & len ) ;
2022-06-16 08:04:58 +00:00
bool ret = false ;
const char * src = ( const char * ) data ;
while ( buf )
{
2022-06-18 00:54:01 +00:00
if ( len > = * bytes - total )
2022-06-16 08:04:58 +00:00
{
memcpy ( buf , src , * bytes - total ) ;
total = * bytes ;
ret = true ;
break ;
}
2022-06-18 00:54:01 +00:00
memcpy ( buf , src , len ) ;
2022-06-16 08:04:58 +00:00
total + = len ;
off + = len ;
src + = len ;
len = * bytes - total ;
buf = buffer ( off , & len ) ;
}
* bytes = total ;
return ret ;
}
2022-06-29 08:13:05 +00:00
bool mapping_buf : : save ( unsigned long long off , mapping_buf * mbuf , unsigned long long src_off )
{
2022-08-05 09:34:18 +00:00
size_t len = ( unsigned int ) ( mbuf - > bytes ( ) - src_off ) ;
unsigned char * buf = mbuf - > buffer ( src_off , ( unsigned int * ) & len ) ;
2022-06-29 08:13:05 +00:00
bool ret = false ;
while ( buf & & save ( buf , & len , off ) )
{
off + = len ;
src_off + = len ;
if ( src_off > = mbuf - > bytes ( ) )
{
ret = true ;
break ;
}
2022-07-18 02:55:01 +00:00
len = ( unsigned int ) ( mbuf - > bytes ( ) - src_off ) ;
2022-08-05 09:34:18 +00:00
buf = mbuf - > buffer ( src_off , ( unsigned int * ) & len ) ;
2022-06-29 08:13:05 +00:00
}
return ret ;
}
2022-06-17 03:50:18 +00:00
int mapping_buf : : read ( void * buf , size_t * bytes , unsigned long long off )
{
if ( ! bytes )
return SCANNER_ERR_INVALID_PARAMETER ;
unsigned int len = * bytes , total = 0 ;
unsigned char * src = buffer ( off , & len ) ,
* dst = ( unsigned char * ) buf ;
int ret = SCANNER_ERR_OUT_OF_RANGE ;
while ( src )
{
if ( len > = * bytes - total )
{
memcpy ( dst , src , * bytes - total ) ;
total = * bytes ;
ret = SCANNER_ERR_OK ;
break ;
}
memcpy ( dst , src , len ) ;
total + = len ;
off + = len ;
len = * bytes - total ;
src = buffer ( off , & len ) ;
}
* bytes = total ;
return ret ;
}
2022-06-16 08:04:58 +00:00
void mapping_buf : : unmap ( )
{
if ( ! is_mem_ )
{
if ( buf_ )
UnmapViewOfFile ( buf_ ) ;
buf_ = NULL ;
offset_ = 0 ;
mapped_bytes_ = 0 ;
}
}
void mapping_buf : : set_remove_file_when_destroyed ( bool rmv )
{
rmv_file_ = rmv ;
}
const char * mapping_buf : : file ( void )
{
2022-06-17 03:50:18 +00:00
return is_mem_ ? " " : file_ . c_str ( ) ;
2022-06-16 08:04:58 +00:00
}
unsigned long long mapping_buf : : bytes ( void )
{
return bytes_ ;
}
unsigned long long mapping_buf : : offset ( void )
{
return offset_ ;
}
unsigned int mapping_buf : : mapped_bytes ( void )
{
return mapped_bytes_ ;
}
2022-06-15 03:04:40 +00:00
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// class scanned_img
2022-06-29 08:13:05 +00:00
scanned_img : : scanned_img ( SANE_Handle dev , SANE_Parameters head , void * data , unsigned int len , int dpi , const wchar_t * tmp_file
2022-06-18 00:54:01 +00:00
, twain_xfer xfer , SANE_FinalImgFormat * fmt ) : head_ ( head ) , dpi_ ( dpi ) , header_size_ ( 0 )
2023-10-08 07:26:18 +00:00
, file_ ( tmp_file ? tmp_file : L " " ) , dev_ ( dev ) , status_ ( IMG_STATUS_OK )
2022-06-18 00:54:01 +00:00
{
2023-12-12 01:14:31 +00:00
const bool prepare_data = false ; // Compatible with apps that have different actual image retrieval modes from the previously set modes, the data is re-organized at fetch - prepare_data_for_transfer
2023-08-04 09:38:26 +00:00
2022-06-18 00:54:01 +00:00
if ( fmt )
fmt_ = * fmt ;
else
{
fmt_ . img_format = SANE_IMAGE_TYPE_BMP ;
fmt_ . detail = 0 ;
}
2022-06-16 08:04:58 +00:00
2022-06-18 00:54:01 +00:00
size_t bytes = line_bytes ( ) * head . lines ;
2023-08-04 09:38:26 +00:00
std : : string h ( file_header ( fmt_ . img_format , ( float ) dpi ) ) ;
2022-06-18 00:54:01 +00:00
unsigned char * dst = NULL , * src = ( unsigned char * ) data ;
bool ok = false ;
header_size_ = h . length ( ) ;
data_ = new mapping_buf ( ) ;
bytes + = header_size_ ;
dst = data_ - > allocate ( tmp_file , bytes ) ;
bytes = h . length ( ) ;
if ( dst & & data_ - > save ( h . c_str ( ) , & bytes , 0 ) )
2022-06-15 03:04:40 +00:00
{
2023-08-04 09:38:26 +00:00
unsigned long long line_l = line_bytes ( ) , off = data_ - > bytes ( ) - line_l ;
2022-06-18 00:54:01 +00:00
unsigned int buf_len = line_bytes ( ) , row = 0 ;
2023-08-04 09:38:26 +00:00
if ( prepare_data & & xfer = = TWAIN_XFER_Memory )
{
2022-06-18 00:54:01 +00:00
line_l * = - 1 ;
2023-08-04 09:38:26 +00:00
off = bytes ;
}
2022-07-18 02:55:01 +00:00
for ( ; row < ( unsigned int ) head . lines ; + + row )
2022-06-15 03:04:40 +00:00
{
2022-06-18 00:54:01 +00:00
bytes = head . bytes_per_line ;
if ( ! data_ - > save ( src , & bytes , off ) )
break ;
off - = line_l ;
src + = head . bytes_per_line ;
2022-06-15 03:04:40 +00:00
}
2022-06-18 00:54:01 +00:00
ok = row = = head . lines ;
2022-06-15 03:04:40 +00:00
}
2023-08-04 09:38:26 +00:00
if ( ! ok )
{
delete data_ ;
data_ = NULL ;
header_size_ = 0 ;
}
else if ( prepare_data )
do_result ( xfer ) ;
2022-06-15 03:04:40 +00:00
}
scanned_img : : ~ scanned_img ( )
{
if ( data_ )
2022-06-16 08:04:58 +00:00
delete data_ ;
2022-06-15 03:04:40 +00:00
}
2022-09-20 10:14:27 +00:00
void scanned_img : : set_image_status ( SANE_Image_Statu status )
{
status_ = status ;
}
2023-08-04 09:38:26 +00:00
std : : string scanned_img : : file_header ( SANE_ImageType type , float resolution )
2022-06-15 03:04:40 +00:00
{
std : : string h ( " " ) ;
2023-08-04 09:38:26 +00:00
if ( type = = SANE_IMAGE_TYPE_BMP )
2022-06-15 03:04:40 +00:00
{
BITMAPINFOHEADER bih = { 0 } ;
2022-06-28 09:17:10 +00:00
int pal_size = 0 ;
2022-06-15 03:04:40 +00:00
bih . biSize = sizeof ( bih ) ;
bih . biWidth = width ( ) ;
bih . biBitCount = depth ( ) ;
bih . biSizeImage = line_bytes ( ) * height ( ) ;
bih . biPlanes = 1 ;
bih . biHeight = height ( ) ;
bih . biCompression = BI_RGB ;
2022-07-18 02:55:01 +00:00
bih . biXPelsPerMeter = bih . biYPelsPerMeter = ( LONG ) ( resolution * 39.37f + .5f ) ;
2022-06-15 03:04:40 +00:00
2022-06-28 09:17:10 +00:00
if ( bih . biBitCount = = 1 )
pal_size = 2 * sizeof ( int ) ;
else if ( bih . biBitCount = = 8 )
pal_size = 256 * sizeof ( int ) ;
2023-12-26 09:24:04 +00:00
bih . biClrUsed = pal_size / sizeof ( int ) ; // some APP (PJScanner.exe <20> <> <EFBFBD> <EFBFBD> ) use this field to calculate pallete
2022-06-28 09:17:10 +00:00
2022-06-16 09:28:46 +00:00
{
BITMAPFILEHEADER fh = { 0 } ;
fh . bfType = MAKEWORD ( ' B ' , ' M ' ) ;
2022-09-09 08:50:32 +00:00
fh . bfSize = sizeof ( fh ) + bih . biSizeImage + sizeof ( bih ) + pal_size ;
2022-06-28 09:17:10 +00:00
fh . bfOffBits = sizeof ( fh ) + sizeof ( bih ) + pal_size ;
2022-06-16 09:28:46 +00:00
h = std : : string ( ( char * ) & fh , sizeof ( fh ) ) ;
}
h + = std : : string ( ( char * ) & bih , sizeof ( bih ) ) ;
2023-07-03 04:23:44 +00:00
pal_size_ = pal_size ;
2022-06-28 09:17:10 +00:00
if ( bih . biBitCount = = 1 )
{
int pal [ ] = { 0 , 0x0ffffff } ;
h + = std : : string ( ( char * ) pal , pal_size ) ;
}
else if ( bih . biBitCount = = 8 )
{
static unsigned int g_bmp8_pallete [ 256 ] = { 0 } ;
if ( g_bmp8_pallete [ 1 ] = = 0 )
{
for ( int i = 1 ; i < _countof ( g_bmp8_pallete ) ; + + i )
g_bmp8_pallete [ i ] = MAKELONG ( MAKEWORD ( i , i ) , MAKEWORD ( i , 0 ) ) ;
}
h + = std : : string ( ( char * ) g_bmp8_pallete , pal_size ) ;
}
2022-06-15 03:04:40 +00:00
}
return h ;
}
2023-08-04 09:38:26 +00:00
void scanned_img : : do_result ( twain_xfer xfer )
2022-06-18 00:54:01 +00:00
{
2023-08-04 09:38:26 +00:00
if ( fmt_ . img_format = = SANE_IMAGE_TYPE_BMP & &
fmt_ . compress . compression = = SANE_COMPRESSION_GROUP4 & &
xfer = = TWAIN_XFER_Memory )
2022-06-18 00:54:01 +00:00
{
2023-08-04 09:38:26 +00:00
// convert to black-white ...
2023-08-03 01:09:58 +00:00
size_t size = data_ - > bytes ( ) ;
2023-08-04 09:38:26 +00:00
mapping_buf * buf = new mapping_buf ( ) ;
std : : wstring file ( file_ + L " .tmp " ) ;
unsigned long long off = 0 ;
2022-06-29 08:13:05 +00:00
2023-08-03 01:09:58 +00:00
if ( buf - > allocate ( file . c_str ( ) , size , true ) & &
buf - > save ( 0 , data_ ) )
2023-08-04 09:38:26 +00:00
{
SANE_ImageFormatConvert conv ;
std : : string sf ( local_trans : : u2a ( file . c_str ( ) ) ) , tifff ( sf + " .tiff " ) ;
bool conv_2_file = false ;
buf - > unmap ( ) ;
conv . src . data = sf . c_str ( ) ;
conv . src . data_len = sf . length ( ) ;
conv . src . fmt . img_format = SANE_IMAGE_TYPE_BMP ;
conv . src . fmt . compress . compression = SANE_COMPRESSION_NONE ;
conv . src . is_file = SANE_TRUE ;
conv . dst . data = conv_2_file ? tifff . c_str ( ) : nullptr ;
conv . dst . data_len = conv_2_file ? tifff . length ( ) : 0 ;
conv . dst . fmt . img_format = SANE_IMAGE_TYPE_BMP ;
conv . dst . fmt . compress . compression = SANE_COMPRESSION_GROUP4 ;
conv . dst . fmt . compress . detail = NULL ;
conv . dst . is_file = conv_2_file ? SANE_TRUE : SANE_FALSE ;
if ( hg_sane_middleware : : instance ( ) - > io_control ( dev_ , IO_CTRL_CODE_CONVERT_IMAGE_FORMAT , & conv , NULL ) = = SANE_STATUS_GOOD )
2022-06-29 08:13:05 +00:00
{
2023-08-04 09:38:26 +00:00
if ( conv_2_file )
2022-06-29 08:13:05 +00:00
{
2023-08-04 09:38:26 +00:00
FILE * src = fopen ( tifff . c_str ( ) , " rb " ) ;
if ( src )
2022-06-29 08:13:05 +00:00
{
delete data_ ;
data_ = new mapping_buf ( ) ;
2023-08-04 09:38:26 +00:00
fseek ( src , 0 , SEEK_END ) ;
size = ftell ( src ) ;
fseek ( src , 0 , SEEK_SET ) ;
data_ - > allocate ( file_ . c_str ( ) , size ) ;
char * mem = new char [ size ] ;
fread ( mem , 1 , size , src ) ;
fclose ( src ) ;
data_ - > save ( mem , & size , 0 ) ;
delete [ ] mem ;
2022-06-29 08:13:05 +00:00
head_ . format = SANE_FRAME_GRAY ;
head_ . depth = 1 ;
head_ . bytes_per_line = ( head_ . pixels_per_line + 7 ) / 8 ;
2023-08-04 09:38:26 +00:00
fmt_ . img_format = SANE_IMAGE_TYPE_TIFF ;
2022-06-29 08:13:05 +00:00
}
2023-08-04 09:38:26 +00:00
remove ( tifff . c_str ( ) ) ;
}
else
{
delete data_ ;
data_ = new mapping_buf ( ) ;
size = conv . dst . data_len ;
data_ - > allocate ( file_ . c_str ( ) , conv . dst . data_len ) ;
data_ - > save ( conv . dst . data , & size , 0 ) ;
hg_sane_middleware : : instance ( ) - > io_control ( dev_ , IO_CTRL_CODE_FREE_MEMORY , ( void * ) conv . dst . data , & conv . dst . data_len ) ;
head_ . format = SANE_FRAME_GRAY ;
head_ . depth = 1 ;
head_ . bytes_per_line = ( head_ . pixels_per_line + 7 ) / 8 ;
fmt_ . img_format = SANE_IMAGE_TYPE_TIFF ;
2022-06-29 08:13:05 +00:00
}
}
}
2023-08-04 09:38:26 +00:00
if ( buf )
delete buf ;
2022-06-18 00:54:01 +00:00
}
2023-08-04 09:38:26 +00:00
else if ( fmt_ . img_format = = SANE_IMAGE_TYPE_BMP
& & channel ( ) = = 3
& & xfer ! = TWAIN_XFER_Memory )
2022-06-18 00:54:01 +00:00
{
2023-08-04 09:38:26 +00:00
// swap RGB
swap_rgb ( ) ;
2022-06-18 00:54:01 +00:00
}
2023-08-04 09:38:26 +00:00
data_ - > unmap ( ) ;
data_done_ = true ;
2022-06-18 00:54:01 +00:00
}
void scanned_img : : swap_rgb ( void )
{
unsigned long long off = 0 ;
unsigned int line = line_bytes ( ) , len = line ;
unsigned char * dst = NULL ;
for ( int i = 0 ; i < height ( ) ; + + i )
{
int l = head_ . bytes_per_line , cur = 0 ;
off = i * line + header_size_ ;
while ( l > 0 )
{
len = l ;
dst = data_ - > buffer ( off + cur , & len ) ;
if ( ! dst )
break ;
2022-07-18 02:55:01 +00:00
if ( len > ( unsigned int ) l )
2022-06-18 00:54:01 +00:00
len = l ;
len / = 3 ;
2022-07-18 02:55:01 +00:00
for ( int pos = 0 ; pos < ( int ) len ; + + pos )
2022-06-18 00:54:01 +00:00
{
unsigned char uc = dst [ pos * 3 + 0 ] ;
dst [ pos * 3 + 0 ] = dst [ pos * 3 + 2 ] ;
dst [ pos * 3 + 2 ] = uc ;
}
l - = len * 3 ;
cur + = len * 3 ;
}
if ( ! dst )
break ;
}
}
2022-06-15 03:04:40 +00:00
// IRef
COM_API_IMPLEMENT ( scanned_img , long , add_ref ( void ) )
{
return refer : : add_ref ( ) ;
}
COM_API_IMPLEMENT ( scanned_img , long , release ( void ) )
{
return refer : : release ( ) ;
}
// IScanImg
COM_API_IMPLEMENT ( scanned_img , int , width ( void ) )
{
return head_ . pixels_per_line ;
}
COM_API_IMPLEMENT ( scanned_img , int , line_bytes ( void ) )
{
2022-06-29 08:13:05 +00:00
if ( fmt_ . img_format = = SANE_IMAGE_TYPE_BMP & & head_ . depth > = 8 )
2022-06-17 03:50:18 +00:00
return ( head_ . bytes_per_line + 3 ) / 4 * 4 ;
else
return head_ . bytes_per_line ;
2022-06-15 03:04:40 +00:00
}
COM_API_IMPLEMENT ( scanned_img , int , height ( void ) )
{
return head_ . lines ;
}
COM_API_IMPLEMENT ( scanned_img , int , depth ( void ) )
{
if ( head_ . format = = SANE_FRAME_RGB )
return head_ . depth * 3 ;
else
return head_ . depth ;
}
COM_API_IMPLEMENT ( scanned_img , int , channel ( void ) )
{
return head_ . format = = SANE_FRAME_RGB ? 3 : 1 ;
}
2022-11-06 08:49:30 +00:00
COM_API_IMPLEMENT ( scanned_img , int , dpi ( void ) )
{
return dpi_ ;
}
2022-06-15 03:04:40 +00:00
COM_API_IMPLEMENT ( scanned_img , SANE_Frame , type ( void ) )
{
return head_ . format ;
}
COM_API_IMPLEMENT ( scanned_img , unsigned int , bytes ( void ) )
{
2022-07-18 02:55:01 +00:00
return data_ ? ( unsigned int ) data_ - > bytes ( ) : 0 ;
2022-06-15 03:04:40 +00:00
}
2022-06-17 03:50:18 +00:00
COM_API_IMPLEMENT ( scanned_img , unsigned int , header_size ( void ) )
{
return header_size_ ;
}
2022-06-16 08:04:58 +00:00
COM_API_IMPLEMENT ( scanned_img , unsigned char * , data ( unsigned long long off , unsigned int * bytes ) )
2022-06-15 03:04:40 +00:00
{
2022-06-16 08:04:58 +00:00
return data_ ? data_ - > buffer ( off , bytes ) : NULL ;
}
2022-06-17 03:50:18 +00:00
COM_API_IMPLEMENT ( scanned_img , int , read ( void * buf , size_t * bytes , unsigned long long off ) )
{
return data_ ? data_ - > read ( buf , bytes , off ) : SCANNER_ERR_NO_DATA ;
}
2022-06-16 08:04:58 +00:00
COM_API_IMPLEMENT ( scanned_img , const char * , file ( void ) )
{
if ( data_ )
return data_ - > file ( ) ;
else
2022-06-17 03:50:18 +00:00
return " " ;
2022-06-16 08:04:58 +00:00
}
COM_API_IMPLEMENT ( scanned_img , void , keep_file ( bool keep ) )
{
if ( data_ )
data_ - > set_remove_file_when_destroyed ( ! keep ) ;
2022-06-15 03:04:40 +00:00
}
COM_API_IMPLEMENT ( scanned_img , void , copy_header ( SANE_Parameters * head ) )
{
* head = head_ ;
}
2022-09-20 10:14:27 +00:00
COM_API_IMPLEMENT ( scanned_img , int , image_status ( void ) )
{
return status_ ;
}
2023-07-03 04:23:44 +00:00
COM_API_IMPLEMENT ( scanned_img , size_t , get_bits_offset ( void ) )
{
if ( fmt_ . img_format = = SANE_IMAGE_TYPE_BMP )
return sizeof ( BITMAPFILEHEADER ) + sizeof ( BITMAPINFOHEADER ) + pal_size_ ;
else
return 0 ;
}
2022-06-18 00:54:01 +00:00
2023-08-04 09:38:26 +00:00
void scanned_img : : prepare_data_for_transfer ( twain_xfer xfer )
{
if ( fmt_ . img_format ! = SANE_IMAGE_TYPE_BMP | | ! data_ | | data_done_ )
return ;
//if ((xfer == TWAIN_XFER_Memory && mem_xfer_data_) ||
// (xfer != TWAIN_XFER_Memory && !mem_xfer_data_))
// return;
//
if ( xfer = = TWAIN_XFER_Memory )
{
// reverse line
int line_l = line_bytes ( ) ,
rows = height ( ) ;
unsigned char * buf = new unsigned char [ line_l ] ,
* buf1 = new unsigned char [ line_l ] ;
unsigned long long first = get_bits_offset ( ) ,
last = first + ( rows - 1 ) * line_l ;
for ( int i = 0 ; i < rows / 2 ; + + i )
{
size_t want = line_l , want1 = line_l ;
data_ - > read ( buf , & want , first ) ;
data_ - > read ( buf1 , & want1 , last ) ;
data_ - > save ( buf1 , & want1 , first ) ;
data_ - > save ( buf , & want , last ) ;
first + = line_l ;
last - = line_l ;
}
}
do_result ( xfer ) ;
}
2022-06-18 00:54:01 +00:00
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// class safe_img_queue
safe_img_queue : : safe_img_queue ( )
{ }
safe_img_queue : : ~ safe_img_queue ( )
{
clear ( ) ;
}
2022-07-02 09:27:21 +00:00
void __stdcall safe_img_queue : : access_image ( scanned_img * img )
2022-06-18 00:54:01 +00:00
{
2022-07-02 09:27:21 +00:00
img - > add_ref ( ) ;
2022-06-18 00:54:01 +00:00
}
2022-07-02 09:27:21 +00:00
void __stdcall safe_img_queue : : free_image ( scanned_img * img )
2022-06-18 00:54:01 +00:00
{
2022-07-02 09:27:21 +00:00
img - > release ( ) ;
2022-06-18 00:54:01 +00:00
}
2022-07-02 09:27:21 +00:00
2022-11-06 08:49:30 +00:00
bool safe_img_queue : : get_header ( SANE_Parameters * header , size_t * bytes , int * dpi )
2022-06-18 00:54:01 +00:00
{
2022-07-02 09:27:21 +00:00
scanned_img * img = take ( false , & safe_img_queue : : access_image ) ;
bool ok = false ;
2022-06-18 00:54:01 +00:00
2022-06-29 08:13:05 +00:00
if ( bytes )
* bytes = 0 ;
2022-07-02 09:27:21 +00:00
if ( img )
2022-06-18 00:54:01 +00:00
{
2022-06-29 08:13:05 +00:00
if ( header )
2022-07-02 09:27:21 +00:00
img - > copy_header ( header ) ;
2022-06-29 08:13:05 +00:00
if ( bytes )
2022-07-02 09:27:21 +00:00
* bytes = img - > bytes ( ) ;
2022-11-06 08:49:30 +00:00
if ( dpi )
* dpi = img - > dpi ( ) ;
2022-06-18 00:54:01 +00:00
ok = true ;
2022-07-02 09:27:21 +00:00
img - > release ( ) ;
2022-06-18 00:54:01 +00:00
}
return ok ;
}
void safe_img_queue : : clear ( )
{
2022-07-02 09:27:21 +00:00
safe_queue < scanned_img * > : : clear ( & safe_img_queue : : free_image ) ;
2022-06-18 00:54:01 +00:00
}