803 lines
18 KiB
C++
803 lines
18 KiB
C++
#include "scanned_img.h"
|
||
|
||
#include <Windows.h>
|
||
#include <Shlwapi.h>
|
||
#pragma comment(lib, "Shlwapi.lib")
|
||
|
||
#include "../../code_device/hgsane/sane_hg_mdw.h"
|
||
#include "../../sdk/include/lang/app_language.h"
|
||
|
||
|
||
|
||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
//
|
||
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;
|
||
}
|
||
|
||
return std::move(a);
|
||
}
|
||
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;
|
||
}
|
||
|
||
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);
|
||
}
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
// 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;
|
||
}
|
||
|
||
|
||
|
||
|
||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
// class mapping_buf
|
||
const unsigned int max_mem_block = 2 * 1024 * 1024;
|
||
extern void __stdcall log_info(const wchar_t* info, int level);
|
||
|
||
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);
|
||
}
|
||
|
||
{
|
||
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);
|
||
log_info((buf + info + L"\r\n").c_str(), 1);
|
||
}
|
||
}
|
||
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)
|
||
*bytes = mapped_bytes_ - (unsigned int)(off - offset_);
|
||
}
|
||
|
||
unsigned char* mapping_buf::allocate(const wchar_t* file, unsigned long long size, bool force_file)
|
||
{
|
||
close();
|
||
|
||
std::string ansi(local_trans::u2a(file));
|
||
if (force_file || size >= 100 * 1024 * 1024 || PathFileExistsW(file))
|
||
{
|
||
init_map(ansi.c_str(), size);
|
||
}
|
||
else
|
||
{
|
||
try
|
||
{
|
||
buf_ = new unsigned char[(unsigned int)size];
|
||
is_mem_ = true;
|
||
bytes_ = size;
|
||
mapped_bytes_ = (unsigned int)size;
|
||
}
|
||
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_)
|
||
size = (unsigned int)(bytes_ - offset_);
|
||
|
||
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_;
|
||
mapped_bytes_ = (unsigned int)(bytes_ - offset_);
|
||
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;
|
||
unsigned char* buf = buffer(off, &len);
|
||
bool ret = false;
|
||
const char* src = (const char*)data;
|
||
|
||
while (buf)
|
||
{
|
||
if (len >= *bytes - total)
|
||
{
|
||
memcpy(buf, src, *bytes - total);
|
||
total = *bytes;
|
||
ret = true;
|
||
break;
|
||
}
|
||
memcpy(buf, src, len);
|
||
total += len;
|
||
off += len;
|
||
src += len;
|
||
len = *bytes - total;
|
||
buf = buffer(off, &len);
|
||
}
|
||
*bytes = total;
|
||
|
||
return ret;
|
||
}
|
||
bool mapping_buf::save(unsigned long long off, mapping_buf* mbuf, unsigned long long src_off)
|
||
{
|
||
size_t len = (unsigned int)(mbuf->bytes() - src_off);
|
||
unsigned char* buf = mbuf->buffer(src_off, (unsigned int*)&len);
|
||
bool ret = false;
|
||
|
||
while (buf && save(buf, &len, off))
|
||
{
|
||
off += len;
|
||
src_off += len;
|
||
if (src_off >= mbuf->bytes())
|
||
{
|
||
ret = true;
|
||
break;
|
||
}
|
||
len = (unsigned int)(mbuf->bytes() - src_off);
|
||
buf = mbuf->buffer(src_off, (unsigned int*)&len);
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
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;
|
||
}
|
||
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)
|
||
{
|
||
return is_mem_ ? "" : file_.c_str();
|
||
}
|
||
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_;
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
// class scanned_img
|
||
scanned_img::scanned_img(SANE_Handle dev, SANE_Parameters head, void* data, unsigned int len, int dpi, const wchar_t* tmp_file
|
||
, twain_xfer xfer, SANE_FinalImgFormat* fmt) : head_(head), dpi_(dpi), header_size_(0)
|
||
, file_(tmp_file ? tmp_file : L""), dev_(dev), status_(IMG_STATUS_OK)
|
||
{
|
||
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
|
||
|
||
if (fmt)
|
||
fmt_ = *fmt;
|
||
else
|
||
{
|
||
fmt_.img_format = SANE_IMAGE_TYPE_BMP;
|
||
fmt_.detail = 0;
|
||
}
|
||
|
||
size_t bytes = line_bytes() * head.lines;
|
||
std::string h(file_header(fmt_.img_format, (float)dpi));
|
||
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))
|
||
{
|
||
unsigned long long line_l = line_bytes(), off = data_->bytes() - line_l;
|
||
unsigned int buf_len = line_bytes(), row = 0;
|
||
|
||
if (prepare_data && xfer == TWAIN_XFER_Memory)
|
||
{
|
||
line_l *= -1;
|
||
off = bytes;
|
||
}
|
||
|
||
for (; row < (unsigned int)head.lines; ++row)
|
||
{
|
||
bytes = head.bytes_per_line;
|
||
if (!data_->save(src, &bytes, off))
|
||
break;
|
||
off -= line_l;
|
||
src += head.bytes_per_line;
|
||
}
|
||
ok = row == head.lines;
|
||
}
|
||
|
||
if (!ok)
|
||
{
|
||
delete data_;
|
||
data_ = NULL;
|
||
header_size_ = 0;
|
||
}
|
||
else if(prepare_data)
|
||
do_result(xfer);
|
||
}
|
||
scanned_img::~scanned_img()
|
||
{
|
||
if (data_)
|
||
delete data_;
|
||
}
|
||
|
||
void scanned_img::set_image_status(SANE_Image_Statu status)
|
||
{
|
||
status_ = status;
|
||
}
|
||
|
||
std::string scanned_img::file_header(SANE_ImageType type, float resolution)
|
||
{
|
||
std::string h("");
|
||
|
||
if (type == SANE_IMAGE_TYPE_BMP)
|
||
{
|
||
BITMAPINFOHEADER bih = { 0 };
|
||
int pal_size = 0;
|
||
|
||
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;
|
||
bih.biXPelsPerMeter = bih.biYPelsPerMeter = (LONG)(resolution * 39.37f + .5f);
|
||
|
||
if (bih.biBitCount == 1)
|
||
pal_size = 2 * sizeof(int);
|
||
else if (bih.biBitCount == 8)
|
||
pal_size = 256 * sizeof(int);
|
||
bih.biClrUsed = pal_size / sizeof(int); // some APP (PJScanner.exe <20><><EFBFBD><EFBFBD>) use this field to calculate pallete
|
||
|
||
{
|
||
BITMAPFILEHEADER fh = { 0 };
|
||
fh.bfType = MAKEWORD('B', 'M');
|
||
fh.bfSize = sizeof(fh) + bih.biSizeImage + sizeof(bih) + pal_size;
|
||
fh.bfOffBits = sizeof(fh) + sizeof(bih) + pal_size;
|
||
|
||
h = std::string((char*)&fh, sizeof(fh));
|
||
}
|
||
|
||
h += std::string((char*)&bih, sizeof(bih));
|
||
pal_size_ = pal_size;
|
||
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);
|
||
}
|
||
}
|
||
|
||
return h;
|
||
}
|
||
void scanned_img::do_result(twain_xfer xfer)
|
||
{
|
||
if (fmt_.img_format == SANE_IMAGE_TYPE_BMP &&
|
||
fmt_.compress.compression == SANE_COMPRESSION_GROUP4 &&
|
||
xfer == TWAIN_XFER_Memory)
|
||
{
|
||
// convert to black-white ...
|
||
size_t size = data_->bytes();
|
||
mapping_buf* buf = new mapping_buf();
|
||
std::wstring file(file_ + L".tmp");
|
||
unsigned long long off = 0;
|
||
|
||
if (buf->allocate(file.c_str(), size, true) &&
|
||
buf->save(0, data_))
|
||
{
|
||
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)
|
||
{
|
||
if(conv_2_file)
|
||
{
|
||
FILE* src = fopen(tifff.c_str(), "rb");
|
||
if (src)
|
||
{
|
||
delete data_;
|
||
data_ = new mapping_buf();
|
||
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;
|
||
|
||
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;
|
||
}
|
||
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;
|
||
}
|
||
}
|
||
}
|
||
if (buf)
|
||
delete buf;
|
||
}
|
||
else if (fmt_.img_format == SANE_IMAGE_TYPE_BMP
|
||
&& channel() == 3
|
||
&& xfer != TWAIN_XFER_Memory)
|
||
{
|
||
// swap RGB
|
||
swap_rgb();
|
||
}
|
||
data_->unmap();
|
||
data_done_ = true;
|
||
}
|
||
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;
|
||
if (len > (unsigned int)l)
|
||
len = l;
|
||
len /= 3;
|
||
for (int pos = 0; pos < (int)len; ++pos)
|
||
{
|
||
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;
|
||
}
|
||
}
|
||
|
||
// 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))
|
||
{
|
||
if (fmt_.img_format == SANE_IMAGE_TYPE_BMP && head_.depth >= 8)
|
||
return (head_.bytes_per_line + 3) / 4 * 4;
|
||
else
|
||
return head_.bytes_per_line;
|
||
}
|
||
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;
|
||
}
|
||
COM_API_IMPLEMENT(scanned_img, int, dpi(void))
|
||
{
|
||
return dpi_;
|
||
}
|
||
COM_API_IMPLEMENT(scanned_img, SANE_Frame, type(void))
|
||
{
|
||
return head_.format;
|
||
}
|
||
COM_API_IMPLEMENT(scanned_img, unsigned int, bytes(void))
|
||
{
|
||
return data_ ? (unsigned int)data_->bytes() : 0;
|
||
}
|
||
COM_API_IMPLEMENT(scanned_img, unsigned int, header_size(void))
|
||
{
|
||
return header_size_;
|
||
}
|
||
COM_API_IMPLEMENT(scanned_img, unsigned char*, data(unsigned long long off, unsigned int* bytes))
|
||
{
|
||
return data_ ? data_->buffer(off, bytes) : NULL;
|
||
}
|
||
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;
|
||
}
|
||
|
||
COM_API_IMPLEMENT(scanned_img, const char*, file(void))
|
||
{
|
||
if (data_)
|
||
return data_->file();
|
||
else
|
||
return "";
|
||
}
|
||
COM_API_IMPLEMENT(scanned_img, void, keep_file(bool keep))
|
||
{
|
||
if (data_)
|
||
data_->set_remove_file_when_destroyed(!keep);
|
||
}
|
||
COM_API_IMPLEMENT(scanned_img, void, copy_header(SANE_Parameters* head))
|
||
{
|
||
*head = head_;
|
||
}
|
||
COM_API_IMPLEMENT(scanned_img, int, image_status(void))
|
||
{
|
||
return status_;
|
||
}
|
||
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;
|
||
}
|
||
|
||
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);
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
// class safe_img_queue
|
||
safe_img_queue::safe_img_queue()
|
||
{}
|
||
safe_img_queue::~safe_img_queue()
|
||
{
|
||
clear();
|
||
}
|
||
|
||
void __stdcall safe_img_queue::access_image(scanned_img* img)
|
||
{
|
||
img->add_ref();
|
||
}
|
||
void __stdcall safe_img_queue::free_image(scanned_img* img)
|
||
{
|
||
img->release();
|
||
}
|
||
|
||
bool safe_img_queue::get_header(SANE_Parameters* header, size_t* bytes, int* dpi)
|
||
{
|
||
scanned_img *img = take(false, &safe_img_queue::access_image);
|
||
bool ok = false;
|
||
|
||
if (bytes)
|
||
*bytes = 0;
|
||
if (img)
|
||
{
|
||
if(header)
|
||
img->copy_header(header);
|
||
if(bytes)
|
||
*bytes = img->bytes();
|
||
if (dpi)
|
||
*dpi = img->dpi();
|
||
ok = true;
|
||
img->release();
|
||
}
|
||
|
||
return ok;
|
||
}
|
||
void safe_img_queue::clear()
|
||
{
|
||
safe_queue<scanned_img*>::clear(&safe_img_queue::free_image);
|
||
}
|
||
|