diff --git a/sane/s2t_api.h b/sane/s2t_api.h index 7577258..b54a11c 100644 --- a/sane/s2t_api.h +++ b/sane/s2t_api.h @@ -152,7 +152,7 @@ __declspec(novtable) struct ISaneInvoker : public IRef COM_API_DECLARE(bool, wait_image(DWORD milliseconds = -1)); COM_API_DECLARE(int, get_scanned_images(DWORD milliseconds = 0)); COM_API_DECLARE(IScanImg*, take_first_image(twain_xfer xfer = TWAIN_XFER_Native)); // call 'release' on returned value, plz - COM_API_DECLARE(bool, get_first_image_header(SANE_Parameters* header)); + COM_API_DECLARE(bool, get_first_image_header(SANE_Parameters* header, size_t* bytes = NULL)); COM_API_DECLARE(bool, is_online(void)); COM_API_DECLARE(bool, is_paper_on(void)); @@ -170,6 +170,7 @@ __declspec(novtable) struct ISaneInvoker : public IRef COM_API_DECLARE(bool, get_value(int sn, set_opt_value, void* param)); COM_API_DECLARE(int, set_value(int sn, void* val)); COM_API_DECLARE(int, convert_image(SANE_ImageFormatConvert* conv)); + COM_API_DECLARE(void, free_buffer(void* buf, int len)); // SANE options ID ... SANE_OPTION_ID_API(is_multiout); // 多流输出 @@ -264,6 +265,7 @@ __declspec(novtable) struct ISaneInvoker : public IRef // twain COM_API_DECLARE(void, twain_set_transfer(twain_xfer xfer)); + COM_API_DECLARE(void, twain_set_compression(SANE_CompressionType compression, void* detail = NULL)); }; struct delete_scanner diff --git a/sane/scanned_img.cpp b/sane/scanned_img.cpp index 487a594..2e2240e 100644 --- a/sane/scanned_img.cpp +++ b/sane/scanned_img.cpp @@ -188,12 +188,12 @@ void mapping_buf::set_buffer(unsigned char*& buf, unsigned long long off, unsign *bytes = mapped_bytes_ - (off - offset_); } -unsigned char* mapping_buf::allocate(const wchar_t* file, unsigned long long size) +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 (size >= 100 * 1024 * 1024 || PathFileExistsW(file)) + if (force_file || size >= 100 * 1024 * 1024 || PathFileExistsW(file)) { init_map(ansi.c_str(), size); } @@ -270,6 +270,27 @@ bool mapping_buf::save(const void* data, size_t* bytes, unsigned long long off) return ret; } +bool mapping_buf::save(unsigned long long off, mapping_buf* mbuf, unsigned long long src_off) +{ + unsigned int len = mbuf->bytes() - src_off; + unsigned char* buf = mbuf->buffer(src_off, &len); + bool ret = false; + + while (buf && save(buf, &len, off)) + { + off += len; + src_off += len; + if (src_off >= mbuf->bytes()) + { + ret = true; + break; + } + len = mbuf->bytes() - src_off; + buf = mbuf->buffer(src_off, &len); + } + + return ret; +} int mapping_buf::read(void* buf, size_t* bytes, unsigned long long off) { if (!bytes) @@ -334,9 +355,10 @@ unsigned int mapping_buf::mapped_bytes(void) ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // class scanned_img -scanned_img::scanned_img(SANE_Parameters head, SANE_Handle dev, int dpi +scanned_img::scanned_img(SANE_Handle dev, SANE_Parameters head, int dpi , const wchar_t* tmp_file, twain_xfer xfer - , SANE_FinalImgFormat *fmt) : head_(head), dpi_(dpi), header_size_(0) + , SANE_FinalImgFormat *fmt) : head_(head), dpi_(dpi), header_size_(0), file_(tmp_file ? tmp_file : L"") + , dev_(dev) { if (fmt) fmt_ = *fmt; @@ -400,8 +422,9 @@ scanned_img::scanned_img(SANE_Parameters head, SANE_Handle dev, int dpi } do_result(ok, xfer); } -scanned_img::scanned_img(SANE_Parameters head, void* data, unsigned int len, int dpi, const wchar_t* tmp_file +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) { if (fmt) fmt_ = *fmt; @@ -504,7 +527,56 @@ void scanned_img::do_result(bool ok, twain_xfer xfer) { if (ok) { - if (fmt_.img_format == SANE_IMAGE_TYPE_BMP + if (fmt_.img_format == SANE_IMAGE_TYPE_BMP && + fmt_.compress.compression == SANE_COMPRESSION_GROUP4 && + xfer == TWAIN_XFER_Memory) + { + // convert to black-white ... + std::string head(file_header(SANE_IMAGE_TYPE_BMP, dpi_, TWAIN_XFER_File)); + size_t size = head.length(); + mapping_buf* buf = new mapping_buf(); + std::wstring file(file_ + L".tmp"); + unsigned long long off = 0; + + if (buf->allocate(file.c_str(), size + data_->bytes(), true) && + buf->save(head.c_str(), &size, off)) + { + if (buf->save(size, data_)) + { + SANE_ImageFormatConvert conv; + std::string sf(local_trans::u2a(file.c_str())); + + 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 = NULL; + conv.dst.data_len = 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 = false; + if (hg_sane_middleware::instance()->io_control(dev_, IO_CTRL_CODE_CONVERT_IMAGE_FORMAT, &conv, NULL) == SANE_STATUS_GOOD) + { + 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; + } + } + } + if (buf) + delete buf; + } + else if (fmt_.img_format == SANE_IMAGE_TYPE_BMP && channel() == 3 && xfer != TWAIN_XFER_Memory) { @@ -571,7 +643,7 @@ COM_API_IMPLEMENT(scanned_img, int, width(void)) } COM_API_IMPLEMENT(scanned_img, int, line_bytes(void)) { - if (fmt_.img_format == SANE_IMAGE_TYPE_BMP) + 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; @@ -661,14 +733,19 @@ bool safe_img_queue::save(scanned_img* img) return true; } -bool safe_img_queue::get_header(SANE_Parameters* header) +bool safe_img_queue::get_header(SANE_Parameters* header, size_t* bytes) { std::lock_guard lock(que_lock_); bool ok = false; + if (bytes) + *bytes = 0; if (queue_.size()) { - queue_[0]->copy_header(header); + if(header) + queue_[0]->copy_header(header); + if(bytes) + *bytes = queue_[0]->bytes(); ok = true; } diff --git a/sane/scanned_img.h b/sane/scanned_img.h index d2c3efc..f9abe7f 100644 --- a/sane/scanned_img.h +++ b/sane/scanned_img.h @@ -40,9 +40,10 @@ public: ~mapping_buf(); public: - unsigned char* allocate(const wchar_t* file, unsigned long long size = 0); + unsigned char* allocate(const wchar_t* file, unsigned long long size = 0, bool force_file = false); unsigned char* buffer(unsigned long long off, unsigned int* bytes); bool save(const void* data, size_t* bytes, unsigned long long off); + bool save(unsigned long long off, mapping_buf* mbuf, unsigned long long src_off = 0); int read(void* buf, size_t* bytes, unsigned long long off); void unmap(); void set_remove_file_when_destroyed(bool rmv); @@ -56,6 +57,8 @@ class scanned_img : public IScanImg, virtual public refer SANE_Parameters head_; mapping_buf* data_; int dpi_; + SANE_Handle dev_; + std::wstring file_; unsigned int header_size_; SANE_FinalImgFormat fmt_; @@ -64,9 +67,9 @@ class scanned_img : public IScanImg, virtual public refer void swap_rgb(void); public: - scanned_img(SANE_Parameters head, SANE_Handle dev, int dpi, const wchar_t* tmp_file + scanned_img(SANE_Handle dev, SANE_Parameters head, int dpi, const wchar_t* tmp_file , twain_xfer xfer = TWAIN_XFER_Native, SANE_FinalImgFormat *fmt = NULL); - scanned_img(SANE_Parameters head, void* data, unsigned int len, int dpi, const wchar_t* tmp_file + scanned_img(SANE_Handle dev, SANE_Parameters head, void* data, unsigned int len, int dpi, const wchar_t* tmp_file , twain_xfer xfer = TWAIN_XFER_Native, SANE_FinalImgFormat *fmt = NULL); @@ -107,7 +110,7 @@ public: public: size_t count(void); bool save(scanned_img* img); - bool get_header(SANE_Parameters* header); + bool get_header(SANE_Parameters* header, size_t* bytes = NULL); scanned_img* take(void); void clear(); }; diff --git a/sane/scanner.cpp b/sane/scanner.cpp index 0c6562b..e6fba7d 100644 --- a/sane/scanner.cpp +++ b/sane/scanner.cpp @@ -116,6 +116,7 @@ scanner::scanner(SCANNERID id) : handle_(NULL), id_(id), ex_id_(EXTENSION_ID_BAS CreateDirectoryW(tmp_path_.c_str(), NULL); tmp_path_ += L"\\"; img_fmt_.img_format = SANE_IMAGE_TYPE_BMP; + img_fmt_.compress.compression = SANE_COMPRESSION_NONE; err_ = open(); } @@ -1510,8 +1511,10 @@ COM_API_IMPLEMENT(scanner, int, start(void)) if (ret == SANE_STATUS_GOOD) { unsigned int l = sizeof(img_fmt_); + SANE_CompressionType cmprsn = img_fmt_.compress.compression; if (hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_GET_FINAL_IMAGE_FORMAT, &img_fmt_, &l)) img_fmt_.img_format = SANE_IMAGE_TYPE_BMP; + img_fmt_.compress.compression = cmprsn; working_ = true; } prev_start_result_ = ret; @@ -1576,9 +1579,9 @@ COM_API_IMPLEMENT(scanner, IScanImg*, take_first_image(twain_xfer xfer)) return dynamic_cast(img); } -COM_API_IMPLEMENT(scanner, bool, get_first_image_header(SANE_Parameters* header)) +COM_API_IMPLEMENT(scanner, bool, get_first_image_header(SANE_Parameters* header, size_t* bytes)) { - return images_.get_header(header); + return images_.get_header(header, bytes); } COM_API_IMPLEMENT(scanner, bool, is_online(void)) { @@ -1779,7 +1782,10 @@ COM_API_IMPLEMENT(scanner, int, convert_image(SANE_ImageFormatConvert* conv)) { return hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_CONVERT_IMAGE_FORMAT, conv, NULL); } - +COM_API_IMPLEMENT(scanner, void, free_buffer(void* buf, int len)) +{ + hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_FREE_MEMORY, buf, (unsigned int*)&len); +} // SANE options ID ... SANE_OPTION_ID_IMPLEMENT(is_multiout) @@ -1868,6 +1874,12 @@ COM_API_IMPLEMENT(scanner, void, twain_set_transfer(twain_xfer xfer)) { xfer_ = xfer; } +COM_API_IMPLEMENT(scanner, void, twain_set_compression(SANE_CompressionType compression, void* detail)) +{ + img_fmt_.compress.compression = compression; + img_fmt_.compress.detail = detail; +} + // ui ... COM_API_IMPLEMENT(scanner, bool, ui_show_main(HWND parent)) @@ -1939,8 +1951,8 @@ int scanner::handle_event(int ev_code, void* data, unsigned int* len) wchar_t name[40] = { 0 }; swprintf_s(name, _countof(name) - 1, L"img_%05u.bmp", ++img_ind_); - img = new scanned_img(simg->header, simg->data, simg->bytes, dpi_, (tmp_path_ + name).c_str(), xfer_, &img_fmt_); - if (img->bytes() >= simg->bytes) + img = new scanned_img(handle_, simg->header, simg->data, simg->bytes, dpi_, (tmp_path_ + name).c_str(), xfer_, &img_fmt_); + if (img->bytes() /*>= simg->bytes*/) { images_.save(img); } diff --git a/sane/scanner.h b/sane/scanner.h index 09e3e04..051f286 100644 --- a/sane/scanner.h +++ b/sane/scanner.h @@ -191,13 +191,14 @@ public: COM_API_OVERRIDE(bool, wait_image(DWORD milliseconds = -1)); COM_API_OVERRIDE(int, get_scanned_images(DWORD milliseconds = 0)); COM_API_OVERRIDE(IScanImg*, take_first_image(twain_xfer xfer = TWAIN_XFER_Native)); // call 'release' on returned value, plz - COM_API_OVERRIDE(bool, get_first_image_header(SANE_Parameters* header)); + COM_API_OVERRIDE(bool, get_first_image_header(SANE_Parameters* header, size_t* bytes = NULL)); COM_API_OVERRIDE(bool, is_online(void)); COM_API_OVERRIDE(bool, is_paper_on(void)); COM_API_OVERRIDE(bool, get_option_info(int sn, value_type* type, value_limit* limit, int* bytes)); COM_API_OVERRIDE(bool, get_value(int sn, set_opt_value, void* param)); COM_API_OVERRIDE(int, set_value(int sn, void* val)); COM_API_OVERRIDE(int, convert_image(SANE_ImageFormatConvert* conv)); + COM_API_OVERRIDE(void, free_buffer(void* buf, int len)); // SANE options ID ... SANE_OPTION_ID(is_multiout); @@ -291,6 +292,7 @@ public: // twain COM_API_OVERRIDE(void, twain_set_transfer(twain_xfer xfer)); + COM_API_OVERRIDE(void, twain_set_compression(SANE_CompressionType compression, void* detail = NULL)); // methods: public: diff --git a/twain/brand.h b/twain/brand.h new file mode 100644 index 0000000..90f219a --- /dev/null +++ b/twain/brand.h @@ -0,0 +1,48 @@ +#pragma once + +// Definitions for all versions ... +// +// + +// #define OEM_HANWANG +#define VERSION_MAIN 4 +#define VERSION_SUB 1007 +#define VERSION_BUILD 2022 +#define VERSION_PATCH 6271 + +#define TO_STR(a) #a +#define TO_VER_STR(vs) TO_STR(v##vs) +#define VERSION_STR(a, b, c, d) TO_VER_STR(a.b.c.d) + +#define PRODUCT_ID 100 +#define MAKE_PID(pid) 0x##pid +#define PASTE_DEF(a, b) a##b +#define FINAL_STR(a, b, c) TO_STR(a##b##c) +#define MAKE_NAME(pid) FULL_NAME(PASTE_DEF(G, pid)) +#define FULL_FAMILY(a) FINAL_STR(a, \x20, Series) +#define MAKE_FAMILY(pid) FULL_FAMILY(PASTE_DEF(G, pid)) + +#ifdef OEM_HANWANG + +#define FULL_NAME(a) FINAL_STR(HANVONSCAN\x20, a, \x20TWAIN) +#define PRODUCT_VID 0x2903 +#define PRODUCT_VENDOR "Hanvon" + +#elif defined(OEM_LISICHENG) + +#define FULL_NAME(a) FINAL_STR(LANXUMSCAN\x20, a, \x20TWAIN) +#define PRODUCT_VID 0x31c9 +#define PRODUCT_VENDOR "Lanxum" + +#else + +#define FULL_NAME(a) FINAL_STR(HUAGOSCAN\x20, a, \x20TWAIN) +#define PRODUCT_VID 0x3072 +#define PRODUCT_VENDOR "HUAGO" + +#endif + + +#define PRODUCT_PID MAKE_PID(PRODUCT_ID) +#define PRODUCT_FAMILY MAKE_FAMILY(PRODUCT_ID) +#define PRODUCT_NAME MAKE_NAME(PRODUCT_ID) diff --git a/twain/twain/huagaods.cpp b/twain/twain/huagaods.cpp index 179200c..3a86616 100644 --- a/twain/twain/huagaods.cpp +++ b/twain/twain/huagaods.cpp @@ -760,6 +760,7 @@ Result huagao_ds::identityOpenDs(const Identity& id) // ui_.reset(new twain_ui(local_utility::reg_get_app_installing_path().c_str())); scanner_->set_event_callback(&huagao_ds::scan_event, this); init_support_caps(); + m_fileXfer.setFormat(ImageFileFormat::Bmp); return success(); } @@ -801,16 +802,26 @@ Result huagao_ds::pendingXfersReset(const Identity&, PendingXfers& data) Result huagao_ds::setupMemXferGet(const Identity&, SetupMemXfer& data) { SANE_Parameters head; + size_t total = 0; if (!scanner_.get() || scanner_->get_scanned_images() == 0) return seqError(); - if (scanner_->get_first_image_header(&head)) + if (scanner_->get_first_image_header(&head, &total)) { - int line_bytes = (head.bytes_per_line + 3) / 4 * 4; - data.setMinSize(head.bytes_per_line); - data.setPreferredSize(line_bytes); - data.setMaxSize(line_bytes * head.lines); + if (m_compression == Compression::None) + { + int line_bytes = (head.bytes_per_line + 3) / 4 * 4; + data.setMinSize(head.bytes_per_line); + data.setPreferredSize(line_bytes); + data.setMaxSize(line_bytes * head.lines); + } + else + { + data.setMinSize(total); + data.setPreferredSize(total); + data.setMaxSize(total); + } return success(); } @@ -929,10 +940,20 @@ Result huagao_ds::imageMemXferGet(const Identity& origin, ImageMemXfer& data) } data.setBytesPerRow(line_l); data.setColumns(img->width()); + data.setRows(rows); data.setXOffset(0); data.setYOffset(off / line_l); - data.setCompression(Compression::None); - if (img->read(dst, &want_read, off) == SCANNER_ERR_OK) + data.setCompression(m_compression); + if (m_compression != Compression::None) + { + want_read = img->bytes(); + off = 0; + img->read(dst, &want_read, off); + data.setRows(1); + data.setColumns(want_read); + data.setBytesWritten(want_read); + } + else if (img->read(dst, &want_read, off) == SCANNER_ERR_OK) { want_read /= line_l; data.setRows(want_read); @@ -1233,6 +1254,7 @@ void huagao_ds::init_support_caps(void) auto mech = data.currentItem(); if (Compression::None == mech || mech == Compression::Group4) { m_compression = mech; + scanner_->twain_set_compression((SANE_CompressionType)m_compression); return success(); } else @@ -1446,6 +1468,7 @@ void huagao_ds::init_support_caps(void) auto mech = data.currentItem(); if (mech == XferMech::Native || mech == XferMech::Memory || mech == XferMech::File) { m_capXferMech = mech; + scanner_->twain_set_transfer((twain_xfer)m_capXferMech); return success(); } else { @@ -1662,7 +1685,8 @@ void huagao_ds::init_support_caps(void) //SET_SANE_OPT(ret, scanner_, ex_final_format, &init); //return ret == SCANNER_ERR_OK ? success() : badValue(); } - ImageFileFormat Now = m_fileXfer.format(), Init = (ImageFileFormat)(int)init.img_format; + // ImageFileFormat Now = (ImageFileFormat)(int)now.img_format, Init = (ImageFileFormat)(int)init.img_format; + ImageFileFormat Now = m_fileXfer.format() , Init = Twpp::ImageFileFormat::Bmp; std::list vals; UInt32 i = 0, n = 0; for (const auto& v : all)