diff --git a/sane/s2t_api.h b/sane/s2t_api.h index 58ac9ca..2836c25 100644 --- a/sane/s2t_api.h +++ b/sane/s2t_api.h @@ -137,7 +137,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 int, header_size(void)); COM_API_DECLARE(unsigned char*, data(unsigned long long off, unsigned int *bytes)); + COM_API_DECLARE(int, read(void* buf, size_t* bytes, unsigned long long off = 0)); COM_API_DECLARE(const char*, file(void)); COM_API_DECLARE(void, keep_file(bool keep)); COM_API_DECLARE(void, copy_header(SANE_Parameters* head)); diff --git a/sane/scanned_img.cpp b/sane/scanned_img.cpp index 73fb6c4..d4aac54 100644 --- a/sane/scanned_img.cpp +++ b/sane/scanned_img.cpp @@ -203,7 +203,7 @@ unsigned char* mapping_buf::allocate(const wchar_t* file, unsigned long long siz { buf_ = new unsigned char[size]; is_mem_ = true; - mapped_bytes_ = size; + bytes_ = mapped_bytes_ = size; } catch (...) { @@ -270,6 +270,36 @@ bool mapping_buf::save(const void* data, size_t* bytes, unsigned long long off) 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_) @@ -287,7 +317,7 @@ void mapping_buf::set_remove_file_when_destroyed(bool rmv) } const char* mapping_buf::file(void) { - return is_mem_ ? NULL : file_.c_str(); + return is_mem_ ? "" : file_.c_str(); } unsigned long long mapping_buf::bytes(void) { @@ -305,24 +335,38 @@ unsigned int mapping_buf::mapped_bytes(void) ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // class scanned_img scanned_img::scanned_img(SANE_Parameters head, SANE_Handle dev, int dpi - , const wchar_t* tmp_file, twain_xfer xfer) : head_(head), dpi_(dpi) + , const wchar_t* tmp_file, twain_xfer xfer + , SANE_FinalImgFormat *fmt) : head_(head), dpi_(dpi), header_size_(0) { + if (fmt) + fmt_ = *fmt; + else + { + fmt_.img_format = SANE_IMAGE_TYPE_BMP; + fmt_.detail = 0; + } + size_t bytes = line_bytes() * height(); - std::string h(file_header(SANE_IMAGE_TYPE_BMP, dpi, xfer)); + std::string h(file_header(fmt_.img_format, dpi, xfer)); unsigned char* dst = NULL; bool ok = false; data_ = new mapping_buf(); + header_size_ = h.length(); dst = data_->allocate(tmp_file, bytes + h.length()); if (dst) { - unsigned long long off = 0; + unsigned long long off = 0, total = 0; bytes = h.length(); if (data_->save(h.c_str(), &bytes, off)) { - unsigned int line = line_bytes(), len = line; + unsigned int len = line_bytes(); + unsigned long long line = line_bytes(); - off = data_->bytes() - line; + if (xfer == TWAIN_XFER_Memory) + line *= -1; + else + 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; @@ -330,6 +374,7 @@ scanned_img::scanned_img(SANE_Parameters head, SANE_Handle dev, int dpi { int r = want_to_read > len - rcv ? len - rcv : want_to_read; int ret = hg_sane_middleware::instance()->read(dev, dst + rcv, &r); + total += r; if (ret != SANE_STATUS_GOOD) break; @@ -339,9 +384,10 @@ scanned_img::scanned_img(SANE_Parameters head, SANE_Handle dev, int dpi { want_to_read = head_.bytes_per_line; off -= line; - len = line; + len = line_bytes(); rcv = 0; dst = data_->buffer(off, &len); + total += dif; } else { @@ -349,13 +395,14 @@ scanned_img::scanned_img(SANE_Parameters head, SANE_Handle dev, int dpi dst = data_->buffer(off + rcv, &len); } } + ok = total + h.length() + dif == data_->bytes(); } - ok = off == h.length(); } if (ok) { - if (channel() == 3) + if (fmt_.img_format == SANE_IMAGE_TYPE_BMP && channel() == 3 && + xfer != TWAIN_XFER_Memory) { // swap RGB unsigned long long off = 0; @@ -393,6 +440,7 @@ scanned_img::scanned_img(SANE_Parameters head, SANE_Handle dev, int dpi { delete data_; data_ = NULL; + header_size_ = 0; } } scanned_img::~scanned_img() @@ -405,7 +453,7 @@ std::string scanned_img::file_header(SANE_ImageType type, float resolution, twai { std::string h(""); - if (type == SANE_IMAGE_TYPE_BMP) + if (type == SANE_IMAGE_TYPE_BMP && xfer != TWAIN_XFER_Memory) { BITMAPINFOHEADER bih = { 0 }; @@ -451,7 +499,10 @@ COM_API_IMPLEMENT(scanned_img, int, width(void)) } COM_API_IMPLEMENT(scanned_img, int, line_bytes(void)) { - return (head_.bytes_per_line + 3) / 4 * 4; + if (fmt_.img_format == SANE_IMAGE_TYPE_BMP) + return (head_.bytes_per_line + 3) / 4 * 4; + else + return head_.bytes_per_line; } COM_API_IMPLEMENT(scanned_img, int, height(void)) { @@ -477,16 +528,25 @@ COM_API_IMPLEMENT(scanned_img, unsigned int, bytes(void)) { return data_ ? 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 NULL; + return ""; } COM_API_IMPLEMENT(scanned_img, void, keep_file(bool keep)) { diff --git a/sane/scanned_img.h b/sane/scanned_img.h index fe386d9..b0c4e8a 100644 --- a/sane/scanned_img.h +++ b/sane/scanned_img.h @@ -42,6 +42,7 @@ 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); + int read(void* buf, size_t* bytes, unsigned long long off); void unmap(); void set_remove_file_when_destroyed(bool rmv); const char* file(void); @@ -54,12 +55,14 @@ class scanned_img : public IScanImg, virtual public refer SANE_Parameters head_; mapping_buf* data_; int dpi_; + unsigned int header_size_; + SANE_FinalImgFormat fmt_; std::string file_header(SANE_ImageType type, float resolution, twain_xfer xfer); public: scanned_img(SANE_Parameters head, SANE_Handle dev, int dpi, const wchar_t* tmp_file - , twain_xfer xfer = TWAIN_XFER_Native); + , twain_xfer xfer = TWAIN_XFER_Native, SANE_FinalImgFormat *fmt = NULL); protected: @@ -79,7 +82,9 @@ 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 int, header_size(void)); COM_API_OVERRIDE(unsigned char*, data(unsigned long long off, unsigned int* bytes)); + COM_API_OVERRIDE(int, read(void* buf, size_t* bytes, unsigned long long off = 0)); COM_API_OVERRIDE(const char*, file(void)); COM_API_OVERRIDE(void, keep_file(bool keep)); COM_API_OVERRIDE(void, copy_header(SANE_Parameters* head)); diff --git a/sane/scanner.cpp b/sane/scanner.cpp index 667c6cc..f51db72 100644 --- a/sane/scanner.cpp +++ b/sane/scanner.cpp @@ -1367,6 +1367,12 @@ COM_API_IMPLEMENT(scanner, int, start(void)) if(ret == SANE_STATUS_NO_DOCS && prev_start_result_ == SANE_STATUS_GOOD) ret = hg_sane_middleware::instance()->start(handle_, NULL); + if (ret == SANE_STATUS_GOOD) + { + unsigned int l = sizeof(img_fmt_); + 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; + } prev_start_result_ = ret; return local_utility::sane_statu_2_scanner_err(ret); @@ -1417,8 +1423,9 @@ COM_API_IMPLEMENT(scanner, IScanImg*, take_first_image(twain_xfer xfer)) if (hg_sane_middleware::instance()->get_image_parameters(handle_, &head) == SANE_STATUS_GOOD) { 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(), xfer); + img = new scanned_img(head, handle_, dpi_, (tmp_path_ + name).c_str(), xfer, &img_fmt_); } return dynamic_cast(img); diff --git a/sane/scanner.h b/sane/scanner.h index 95a62d4..d8c945e 100644 --- a/sane/scanner.h +++ b/sane/scanner.h @@ -31,6 +31,7 @@ class scanner : public ISaneInvoker, virtual public refer int dpi_; unsigned int img_ind_; std::wstring tmp_path_; + SANE_FinalImgFormat img_fmt_; int open(void); int close(void); diff --git a/twain/twain/huagaods.cpp b/twain/twain/huagaods.cpp index cb3aa6f..9737857 100644 --- a/twain/twain/huagaods.cpp +++ b/twain/twain/huagaods.cpp @@ -803,16 +803,8 @@ Result huagao_ds::pendingXfersEnd(const Identity& id, PendingXfers& data) } Result huagao_ds::pendingXfersReset(const Identity&, PendingXfers& data) { + pending_xfer_.clear(); data.setCount(scanner_->get_scanned_images(-1)); - //if (scanner_.get()) - // scanner_->stop(); - - //if (scanner.get()) - //{ - // scanner->Stop_scan(); - // scanner->reset(); - // scanner->ResetScanner(); - //} return success(); } @@ -827,7 +819,7 @@ Result huagao_ds::setupMemXferGet(const Identity&, SetupMemXfer& data) { int line_bytes = (head.bytes_per_line + 3) / 4 * 4; data.setMinSize(head.bytes_per_line); - data.setPreferredSize(line_bytes * head.lines); + data.setPreferredSize(line_bytes); data.setMaxSize(line_bytes * head.lines); return success(); @@ -923,36 +915,52 @@ Result huagao_ds::imageLayoutReset(const Identity& origin, ImageLayout& data) } Result huagao_ds::imageMemXferGet(const Identity& origin, ImageMemXfer& data) { - if (!scanner_.get() || scanner_->get_scanned_images() == 0) + if (!scanner_.get() || (scanner_->get_scanned_images() == 0 && !pending_xfer_.img)) return seqError(); - IScanImg *img = scanner_->take_first_image(TWAIN_XFER_Memory); - unsigned long long off = 0; - unsigned int total = img->bytes(); - unsigned char *src = img->data(off, &total), - *dst = NULL; + IScanImg *img = pending_xfer_.img ? pending_xfer_.img : scanner_->take_first_image(TWAIN_XFER_Memory); + unsigned long long off = pending_xfer_.img ? pending_xfer_.off : 0; + unsigned char *dst = (unsigned char*)data.memory().data().data(); + unsigned int line_l = img->line_bytes(), + rows = data.memory().size() / line_l; + size_t want_read = rows * line_l; + Result ret = { ReturnCode::XferDone, ConditionCode::Success }; - data.setBytesPerRow(img->line_bytes()); - data.setColumns(img->width()); - data.setRows(img->height()); - data.setBytesWritten(img->bytes()); - data.setXOffset(0); - data.setYOffset(0); - data.setCompression(Compression::None); - dst = (unsigned char*)data.memory().data().data(); - while (off < img->bytes() && src) + if (rows == 0) + return badValue(); + + if (pending_xfer_.img) { - 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->add_ref(); + pending_xfer_.clear(); + } + data.setBytesPerRow(line_l); + data.setColumns(img->width()); + data.setXOffset(0); + data.setYOffset(off / line_l); + data.setCompression(Compression::None); + if (img->read(dst, &want_read, off) == SCANNER_ERR_OK) + { + want_read /= line_l; + data.setRows(want_read); + want_read *= line_l; + data.setBytesWritten(want_read); + off += want_read; + if (off < img->bytes()) + { + pending_xfer_.img = img; + pending_xfer_.off = off; + img->add_ref(); + ret = success(); + } + } + else + { + ret = { ReturnCode::XferDone, ConditionCode::Bummer }; } img->release(); - return success(); + return ret; } Result huagao_ds::imageNativeXferGet(const Identity& id, ImageNativeXfer& data) { @@ -987,7 +995,10 @@ Result huagao_ds::imageNativeXferGet(const Identity& id, ImageNativeXfer& data) } Twpp::Result huagao_ds::pendingXfersStopFeeder(const Identity& origin, PendingXfers& data) { - // load_sane_util::invoke_sane_cancel(); + if (!scanner_.get()) + return seqError(); + + scanner_->stop(); return success(); } diff --git a/twain/twain/huagaods.hpp b/twain/twain/huagaods.hpp index a221e2d..a8efb8c 100644 --- a/twain/twain/huagaods.hpp +++ b/twain/twain/huagaods.hpp @@ -50,6 +50,22 @@ class huagao_ds : public Twpp::SourceFromThis { void init_support_caps_ex(void); void on_scan_event(int sane_event, void* data, unsigned int* len); + typedef struct _pending_xfer + { + IScanImg* img; + unsigned int off; + + struct _pending_xfer() : img(NULL), off(0) + {} + void clear(void) + { + if (img) + img->release(); + img = NULL; + off = 0; + } + }PENDXFER; + PENDXFER pending_xfer_; public: huagao_ds();