diff --git a/sane/s2t_api.h b/sane/s2t_api.h index a67cf3d..a50aa2c 100644 --- a/sane/s2t_api.h +++ b/sane/s2t_api.h @@ -131,7 +131,9 @@ __declspec(novtable) struct IScanImg : public IRef COM_API_DECLARE(int, channel(void)); COM_API_DECLARE(SANE_Frame, type(void)); COM_API_DECLARE(unsigned int, bytes(void)); - COM_API_DECLARE(unsigned char*, bits(void)); + COM_API_DECLARE(unsigned char*, data(unsigned long long off, unsigned int *bytes)); + COM_API_DECLARE(const char*, file(void)); + COM_API_DECLARE(void, keep_file(bool keep)); COM_API_DECLARE(void, copy_header(SANE_Parameters* head)); }; __declspec(novtable) struct ISaneInvoker : public IRef diff --git a/sane/scanned_img.cpp b/sane/scanned_img.cpp index bdf2f17..1116e9b 100644 --- a/sane/scanned_img.cpp +++ b/sane/scanned_img.cpp @@ -1,9 +1,58 @@ #include "scanned_img.h" #include +#include +#pragma comment(lib, "Shlwapi.lib") + +#include "../../code_device/hgsane/sane_hg_mdw.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 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 u; + } +} + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // class refer refer::refer() : ref_(1) @@ -27,44 +76,328 @@ COM_API_IMPLEMENT(refer, long, release(void)) + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// class scanned_img -scanned_img::scanned_img(SANE_Parameters head, unsigned char* data) : head_(head) +// class mapping_buf +const unsigned int max_mem_block = 2 * 1024 * 1024; + +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) { - size_t bytes = line_bytes() * height(); - std::string h(file_header(SANE_IMAGE_TYPE_BMP, 200.0f)); - unsigned char* src = data + head.bytes_per_line * head.lines - head.bytes_per_line, - * dst = NULL; + SYSTEM_INFO si = { 0 }; - bytes_ = bytes + h.length(); - data_ = new unsigned char[bytes_]; - memcpy(data_, h.c_str(), h.length()); - dst = data_ + h.length(); + GetSystemInfo(&si); + page_size_ = si.dwPageSize; + map_unit_ = si.dwAllocationGranularity; +} +mapping_buf::~mapping_buf() +{ + close(); +} - if (head.format == SANE_FRAME_RGB) +void mapping_buf::init_map(const char* file, unsigned long long size) +{ + HANDLE f = INVALID_HANDLE_VALUE; + + if (size) { - for (int i = 0; i < height(); ++i) + f = CreateFileA(file, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (f != INVALID_HANDLE_VALUE) { - for (int j = 0; j < head.pixels_per_line; ++j) + unsigned long long total = size - 1; + LONG* p32 = (LONG*)&total; + *p32 = SetFilePointer(f, *p32, p32 + 1, FILE_BEGIN); + total++; + if (total == size) { - dst[j * 3 + 0] = src[j * 3 + 2]; - dst[j * 3 + 1] = src[j * 3 + 1]; - dst[j * 3 + 2] = src[j * 3 + 0]; + DWORD wrote = 1; + WriteFile(f, "\0", 1, &wrote, NULL); + map_ = CreateFileMapping(f, NULL, PAGE_READWRITE, p32[1], p32[0], NULL); } - src -= head.bytes_per_line; - dst += line_bytes(); + CloseHandle(f); + if (!map_) + DeleteFileA(file); } } else { - for (int i = 0; i < height(); ++i, dst += line_bytes(), src -= head.bytes_per_line) - memcpy(dst, src, head.bytes_per_line); + 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_ - (off - offset_); +} + +unsigned char* mapping_buf::allocate(const wchar_t* file, unsigned long long size) +{ + close(); + + std::string ansi(local_trans::u2a(file)); + if (size >= 100 * 1024 * 1024 || PathFileExistsW(file)) + { + init_map(ansi.c_str(), size); + } + else + { + try + { + buf_ = new unsigned char[size]; + is_mem_ = true; + mapped_bytes_ = 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 = 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_ = 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, data, len); + total += len; + off += len; + src += len; + len = *bytes - total; + buf = 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_ ? NULL : 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_Parameters head, SANE_Handle dev, int dpi, const wchar_t* tmp_file) : head_(head), dpi_(dpi) +{ + size_t bytes = line_bytes() * height(); + std::string h(file_header(SANE_IMAGE_TYPE_BMP, dpi)); + unsigned char* dst = NULL; + bool ok = false; + + data_ = new mapping_buf(); + dst = data_->allocate(tmp_file, bytes + h.length()); + if (dst) + { + unsigned long long off = 0; + bytes = h.length(); + if (data_->save(h.c_str(), &bytes, off)) + { + unsigned int line = line_bytes(), len = line; + + off = data_->bytes() - line; + dst = data_->buffer(off, &len); + + int want_to_read = head_.bytes_per_line, rcv = 0, dif = line_bytes() - head_.bytes_per_line; + while (dst) + { + int r = want_to_read > len - rcv ? len - rcv : want_to_read; + int ret = hg_sane_middleware::instance()->read(dev, dst + rcv, &r); + if (ret != SANE_STATUS_GOOD) + break; + + want_to_read -= r; + rcv += r; + if (want_to_read == 0) + { + want_to_read = head_.bytes_per_line; + off -= line; + len = line; + rcv = 0; + dst = data_->buffer(off, &len); + } + else + { + len = want_to_read; + dst = data_->buffer(off + rcv, &len); + } + } + } + ok = off == h.length(); + } + + if (ok) + { + if (channel() == 3) + { + // swap RGB + unsigned long long off = 0; + unsigned int line = line_bytes(), len = line; + for (int i = 0; i < height(); ++i) + { + int l = head_.bytes_per_line, cur = 0; + + off = i * line + h.length(); + while (l > 0) + { + len = l; + dst = data_->buffer(off + cur, &len); + if (!dst) + break; + if (len > l) + len = l; + len /= 3; + for (int pos = 0; pos < 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; + } + } + data_->unmap(); + } + else + { + delete data_; + data_ = NULL; } } scanned_img::~scanned_img() { if (data_) - delete[] data_; + delete data_; } std::string scanned_img::file_header(SANE_ImageType type, float resolution) @@ -131,11 +464,23 @@ COM_API_IMPLEMENT(scanned_img, SANE_Frame, type(void)) } COM_API_IMPLEMENT(scanned_img, unsigned int, bytes(void)) { - return bytes_; + return data_ ? data_->bytes() : 0; } -COM_API_IMPLEMENT(scanned_img, unsigned char*, bits(void)) +COM_API_IMPLEMENT(scanned_img, unsigned char*, data(unsigned long long off, unsigned int* bytes)) { - return data_; + return data_ ? data_->buffer(off, bytes) : NULL; +} +COM_API_IMPLEMENT(scanned_img, const char*, file(void)) +{ + if (data_) + return data_->file(); + else + return NULL; +} +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)) { diff --git a/sane/scanned_img.h b/sane/scanned_img.h index af45c83..ac0cfe8 100644 --- a/sane/scanned_img.h +++ b/sane/scanned_img.h @@ -16,16 +16,49 @@ public: COM_API_OVERRIDE(long, release(void)); }; +class mapping_buf +{ + unsigned long long bytes_; + unsigned long long offset_; + unsigned int page_size_; + unsigned int map_unit_; + unsigned int mapped_bytes_; + HANDLE map_; + bool is_mem_; + unsigned char* buf_; + std::string file_; + bool rmv_file_; + + void init_map(const char* file, unsigned long long size); + void close(void); + void map(void); + void set_buffer(unsigned char*& buf, unsigned long long off, unsigned int* bytes); + +public: + mapping_buf(); + ~mapping_buf(); + +public: + unsigned char* allocate(const wchar_t* file, unsigned long long size = 0); + unsigned char* buffer(unsigned long long off, unsigned int* bytes); + bool save(const void* data, size_t* bytes, unsigned long long off); + void unmap(); + void set_remove_file_when_destroyed(bool rmv); + const char* file(void); + unsigned long long bytes(void); + unsigned long long offset(void); + unsigned int mapped_bytes(void); +}; class scanned_img : public IScanImg, virtual public refer { SANE_Parameters head_; - unsigned char* data_; - unsigned int bytes_; + mapping_buf* data_; + int dpi_; std::string file_header(SANE_ImageType type, float resolution); public: - scanned_img(SANE_Parameters head, unsigned char* data); + scanned_img(SANE_Parameters head, SANE_Handle dev, int dpi, const wchar_t* tmp_file); protected: @@ -45,7 +78,14 @@ public: COM_API_OVERRIDE(int, channel(void)); COM_API_OVERRIDE(SANE_Frame, type(void)); COM_API_OVERRIDE(unsigned int, bytes(void)); - COM_API_OVERRIDE(unsigned char*, bits(void)); + COM_API_OVERRIDE(unsigned char*, data(unsigned long long off, unsigned int* bytes)); + COM_API_OVERRIDE(const char*, file(void)); + COM_API_OVERRIDE(void, keep_file(bool keep)); COM_API_OVERRIDE(void, copy_header(SANE_Parameters* head)); }; +namespace local_trans +{ + std::string u2a(const wchar_t* unic, UINT cp = CP_ACP); + std::wstring a2u(const char* asc, UINT cp = CP_ACP); +} diff --git a/sane/scanner.cpp b/sane/scanner.cpp index 6d29bf9..3ca29f9 100644 --- a/sane/scanner.cpp +++ b/sane/scanner.cpp @@ -21,7 +21,13 @@ static IMPLEMENT_OPTION_STRING_COMPARE(compare_sane_opt); ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // class scanner scanner::scanner(SCANNERID id) : handle_(NULL), id_(id), ex_id_(EXTENSION_ID_BASE), prev_start_result_(SCANNER_ERR_NOT_START) + , dpi_(200), tmp_path_(L""), img_ind_(0) { + tmp_path_ = local_trans::a2u(hg_sane_middleware::sane_path().c_str()); + tmp_path_ += L"imgs"; + CreateDirectoryW(tmp_path_.c_str(), NULL); + tmp_path_ += L"\\"; + err_ = open(); } scanner::~scanner() @@ -419,32 +425,50 @@ int scanner::set_option_value(int sn, SANE_Value_Type type, int size, void* data SANE_Int si = 0, after = 0; SANE_Fixed sf = 0; int ret = SCANNER_ERR_OK; + void* val = data; if (type == SANE_TYPE_BOOL) { sb = *(bool*)data ? SANE_TRUE : SANE_FALSE; - data = &sb; + val = &sb; } else if (type == SANE_TYPE_INT) { si = *(int*)data; - data = &si; + val = &si; } else if (type == SANE_TYPE_FIXED) { sf = SANE_FIX(*(float*)data); - data = &sf; + val = &sf; } else { buf = new char[size + 4]; memset(buf, 0, size + 4); strcpy(buf, ((std::string*)data)->c_str()); - data = buf; + val = buf; } - ret = hg_sane_middleware::instance()->set_option(handle_, sn, SANE_ACTION_SET_VALUE, data, &after); - if (buf) + + ret = hg_sane_middleware::instance()->set_option(handle_, sn, SANE_ACTION_SET_VALUE, val, &after); + + if (type == SANE_TYPE_BOOL) + { + *(bool*)data = sb == SANE_TRUE; + } + else if (type == SANE_TYPE_INT) + { + *(int*)data = si; + } + else if (type == SANE_TYPE_FIXED) + { + *(float*)data = SANE_UNFIX(sf); + } + else if(buf) + { + strcpy((char*)val, buf); delete[] buf; + } return ret; } @@ -1345,7 +1369,7 @@ COM_API_IMPLEMENT(scanner, int, start(void)) prev_start_result_ = ret; - return ret; + return local_utility::sane_statu_2_scanner_err(ret); } COM_API_IMPLEMENT(scanner, int, stop(void)) { @@ -1392,19 +1416,9 @@ COM_API_IMPLEMENT(scanner, IScanImg*, take_first_image(void)) if (hg_sane_middleware::instance()->get_image_parameters(handle_, &head) == SANE_STATUS_GOOD) { - int off = 0, size = head.bytes_per_line * head.lines, rcv = size; - unsigned char* buf = new unsigned char[size]; - - while (hg_sane_middleware::instance()->read(handle_, buf + off, &rcv) == SANE_STATUS_GOOD) - { - off += rcv; - if (off >= size) - break; - rcv = size - off; - } - - img = new scanned_img(head, buf); - delete[] buf; + wchar_t name[40] = { 0 }; + swprintf_s(name, _countof(name) - 1, L"img_%05u.bmp", ++img_ind_); + img = new scanned_img(head, handle_, dpi_, (tmp_path_ + name).c_str()); } return dynamic_cast(img); @@ -1476,6 +1490,8 @@ COM_API_IMPLEMENT(scanner, bool, get_value(int sn, set_opt_value setval, void* p hg_sane_middleware::instance()->get_cur_value(handle_, sn, &cur); val = cur; + if (sn == resolution_id_) + dpi_ = cur; do { if (desc->constraint_type == SANE_CONSTRAINT_RANGE) @@ -1508,6 +1524,8 @@ COM_API_IMPLEMENT(scanner, bool, get_value(int sn, set_opt_value setval, void* p float val = .0f; hg_sane_middleware::instance()->get_cur_value(handle_, sn, &cur); + if (sn == resolution_id_) + dpi_ = SANE_UNFIX(cur) + .5f; do { if (desc->constraint_type == SANE_CONSTRAINT_RANGE) @@ -1594,6 +1612,14 @@ COM_API_IMPLEMENT(scanner, int, set_value(int sn, void* val)) ret = (this->*ex->ex_api)(ex->base_ind, val, NULL); } + if (sn == resolution_id_) + { + if (desc->type == SANE_TYPE_FIXED) + dpi_ = *(float*)val + .5f; + else + dpi_ = *(int*)val; + } + return ret; } diff --git a/sane/scanner.h b/sane/scanner.h index 47f783d..879d746 100644 --- a/sane/scanner.h +++ b/sane/scanner.h @@ -28,6 +28,9 @@ class scanner : public ISaneInvoker, virtual public refer int err_; int ex_id_; int prev_start_result_; + int dpi_; + unsigned int img_ind_; + std::wstring tmp_path_; int open(void); int close(void); diff --git a/twain/twain/huagaods.cpp b/twain/twain/huagaods.cpp index 16c5c7f..aae394e 100644 --- a/twain/twain/huagaods.cpp +++ b/twain/twain/huagaods.cpp @@ -926,7 +926,9 @@ Result huagao_ds::imageMemXferGet(const Identity& origin, ImageMemXfer& data) return seqError(); IScanImg *img = scanner_->take_first_image(); - unsigned char *src = img->bits() + img->bytes() - img->line_bytes(), + unsigned long long off = 0; + unsigned int total = img->bytes(); + unsigned char *src = img->data(off, &total), *dst = NULL; data.setBytesPerRow(img->line_bytes()); @@ -937,8 +939,16 @@ Result huagao_ds::imageMemXferGet(const Identity& origin, ImageMemXfer& data) data.setYOffset(0); data.setCompression(Compression::None); dst = (unsigned char*)data.memory().data().data(); - for (int i = 0; i < img->height(); ++i, src -= img->line_bytes(), dst += img->line_bytes()) - std::copy(src, src + img->line_bytes(), dst); + while (off < img->bytes() && src) + { + std::copy(src, src + total, dst); + dst += total; + off += total; + if (off >= img->bytes()) + break; + total = img->bytes() - off; + src = img->data(off, &total); + } img->release(); return success(); @@ -955,7 +965,21 @@ Result huagao_ds::imageNativeXferGet(const Identity& id, ImageNativeXfer& data) if (data) data.release(); data = ImageNativeXfer(img->bytes()); - std::copy(img->bits(), img->bits() + img->bytes(), data.data().data()); + + unsigned long long off = 0; + unsigned int total = img->bytes(); + unsigned char* src = img->data(off, &total), + * dst = data.data().data(); + while (off < img->bytes() && src) + { + std::copy(src, src + total, dst); + dst += total; + off += total; + if (off >= img->bytes()) + break; + total = img->bytes() - off; + src = img->data(off, &total); + } img->release(); return { ReturnCode::XferDone, ConditionCode::Success }; @@ -978,17 +1002,43 @@ Twpp::Result huagao_ds::imageFileXferGet(const Twpp::Identity& origin) if (img) { - dst = fopen(m_fileXfer.filePath().string().c_str(), "wb"); - ret = { ReturnCode::Failure, ConditionCode::FileWriteError }; - if (dst) + std::string file(img->file()); + if (file.empty()) { - if(fwrite(img->bits(), 1, img->bytes(), dst) == img->bytes()) - ret = Result(ReturnCode::XferDone, ConditionCode::Success); + dst = fopen(m_fileXfer.filePath().string().c_str(), "wb"); + ret = { ReturnCode::Failure, ConditionCode::FileWriteError }; + if (dst) + { + unsigned long long off = 0; + unsigned int total = img->bytes(); + unsigned char* src = img->data(off, &total); + while (src) + { + if (fwrite(src, 1, total, dst) != total) + break; + off += total; + if (off >= img->bytes()) + { + ret = Result(ReturnCode::XferDone, ConditionCode::Success); + break; + } + total = img->bytes() - off; + src = img->data(off, &total); + } - fclose(dst); + fclose(dst); + } + img->release(); + } + else + { + img->keep_file(true); + img->release(); + if (MoveFileA(file.c_str(), m_fileXfer.filePath().string().c_str())) + ret = Result(ReturnCode::XferDone, ConditionCode::Success); + else + DeleteFileA(file.c_str()); } - - img->release(); } return ret;