| |
| |
| #include "tscanner.h" |
| #include "tscannertwain.h" |
| #include "texception.h" |
| #include "tscannerepson.h" |
| #include "tstream.h" |
| #include "tconvert.h" |
| #include "tfilepath.h" |
| #include "tfilepath_io.h" |
| #include "tenv.h" |
| #include "tsystem.h" |
| |
| extern "C" { |
| #include "../common/twain/ttwain_util.h" |
| } |
| |
| |
| |
| |
| |
| |
| |
| void TScanParam::update(const TScanParam &model) { |
| m_supported = model.m_supported; |
| m_min = model.m_min; |
| m_max = model.m_max; |
| m_def = model.m_def; |
| m_step = model.m_step; |
| m_value = tcrop(m_value, m_min, m_max); |
| } |
| |
| |
| |
| |
| |
| |
| |
| const std::string BlackAndWhite = "Black & White"; |
| const std::string Graytones = "Graytones"; |
| const std::string Rgbcolors = "RGB Color"; |
| |
| |
| |
| TScannerParameters::TScannerParameters() |
| : m_bw(false) |
| , m_gray(false) |
| , m_rgb(false) |
| , m_scanType(None) |
| , m_scanArea(TRectD()) |
| , m_cropBox(TRectD()) |
| , m_isPreview(false) |
| , m_maxPaperSize(TDimensionD(0, 0)) |
| , m_paperOverflow(false) |
| , m_brightness() |
| , m_contrast() |
| , m_threshold() |
| , m_dpi() |
| , m_paperFeeder() |
| , m_twainVersion() |
| , m_manufacturer() |
| , m_prodFamily() |
| , m_productName() |
| , m_version() |
| , m_reverseOrder(false) |
| , m_validatedByCurrentScanner(false) { |
| m_threshold.m_value = 127; |
| m_brightness.m_value = 127; |
| } |
| |
| |
| |
| TScannerParameters::~TScannerParameters() {} |
| |
| |
| |
| void TScannerParameters::assign(const TScannerParameters *src) { *this = *src; } |
| |
| |
| |
| void TScannerParameters::setSupportedTypes(bool bw, bool gray, bool rgb) { |
| m_bw = bw; |
| m_gray = gray; |
| m_rgb = rgb; |
| if (!m_bw && !m_gray && !m_rgb) { |
| m_scanType = None; |
| } else { |
| switch (m_scanType) { |
| case BW: |
| if (!m_bw) m_scanType = m_gray ? GR8 : RGB24; |
| break; |
| case GR8: |
| if (!m_gray) m_scanType = m_rgb ? RGB24 : BW; |
| break; |
| case RGB24: |
| if (!m_rgb) m_scanType = m_gray ? GR8 : BW; |
| break; |
| case None: |
| if (gray) |
| m_scanType = GR8; |
| else { |
| if (rgb) |
| m_scanType = RGB24; |
| else if (bw) |
| m_scanType = BW; |
| } |
| break; |
| } |
| } |
| } |
| |
| |
| |
| bool TScannerParameters::isSupported(ScanType scanType) const { |
| switch (scanType) { |
| case BW: |
| return m_bw; |
| case GR8: |
| return m_gray; |
| case RGB24: |
| return m_rgb; |
| default: |
| assert(0); |
| return false; |
| } |
| } |
| |
| |
| |
| void TScannerParameters::cropScanArea() { |
| m_paperOverflow = false; |
| if (m_maxPaperSize.lx == 0 || m_maxPaperSize.ly == 0) { |
| |
| |
| return; |
| } |
| assert(m_maxPaperSize.lx > 0 && m_maxPaperSize.ly > 0); |
| if (m_scanArea.x1 > m_maxPaperSize.lx) { |
| m_paperOverflow = true; |
| m_scanArea.x1 = m_maxPaperSize.lx; |
| } |
| if (m_scanArea.y1 > m_maxPaperSize.ly) { |
| m_paperOverflow = true; |
| m_scanArea.y1 = m_maxPaperSize.ly; |
| } |
| } |
| |
| |
| |
| void TScannerParameters::setMaxPaperSize(double maxWidth, double maxHeight) { |
| |
| m_maxPaperSize = TDimensionD(maxWidth, maxHeight); |
| cropScanArea(); |
| } |
| |
| |
| |
| void TScannerParameters::setPaperFormat(std::string paperFormat) { |
| TPaperFormatManager *formatManager = TPaperFormatManager::instance(); |
| assert(formatManager->isValidFormat(paperFormat)); |
| if (!formatManager->isValidFormat(paperFormat)) |
| paperFormat = formatManager->getDefaultFormat(); |
| m_paperFormat = paperFormat; |
| TDimensionD d = TPaperFormatManager::instance()->getSize(paperFormat); |
| m_scanArea = TRectD(TPointD(0, 0), d); |
| cropScanArea(); |
| if (m_cropBox == TRectD()) m_cropBox = m_scanArea; |
| } |
| |
| |
| |
| void TScannerParameters::updatePaperFormat() { |
| if (m_paperFormat == "") |
| m_paperFormat = TPaperFormatManager::instance()->getDefaultFormat(); |
| setPaperFormat(m_paperFormat); |
| } |
| |
| |
| |
| void TScannerParameters::setScanType(ScanType scanType) { |
| assert(scanType == None || scanType == BW || scanType == GR8 || |
| scanType == RGB24); |
| m_scanType = scanType; |
| } |
| |
| |
| |
| void TScannerParameters::adaptToCurrentScanner() { |
| try { |
| if (TScanner::instance()->isDeviceSelected()) { |
| TScanner::instance()->updateParameters(*this); |
| m_validatedByCurrentScanner = true; |
| } |
| } catch (TException &) { |
| |
| } |
| } |
| |
| |
| |
| void TScannerParameters::saveData(TOStream &os) const { |
| std::map<std::string, std::string> attr; |
| attr["fmt"] = m_paperFormat; |
| os.openCloseChild("paper", attr); |
| |
| if (m_paperFeeder.m_value == 1.0) { |
| attr.clear(); |
| os.openCloseChild("autoFeeder", attr); |
| } |
| |
| if (m_reverseOrder) { |
| attr.clear(); |
| os.openCloseChild("reverseOrder", attr); |
| } |
| |
| if (m_scanType != None) { |
| std::string scanTypeString = Rgbcolors; |
| switch (m_scanType) { |
| case BW: |
| scanTypeString = BlackAndWhite; |
| break; |
| case GR8: |
| scanTypeString = Graytones; |
| break; |
| case RGB24: |
| scanTypeString = Rgbcolors; |
| break; |
| } |
| attr.clear(); |
| attr["value"] = scanTypeString; |
| os.openCloseChild("mode", attr); |
| } |
| |
| if (m_dpi.m_supported) { |
| attr.clear(); |
| attr["value"] = std::to_string(m_dpi.m_value); |
| os.openCloseChild("dpi", attr); |
| } |
| |
| if (m_brightness.m_supported) { |
| attr.clear(); |
| attr["value"] = std::to_string(m_brightness.m_value); |
| os.openCloseChild("brightness", attr); |
| } |
| |
| if (m_contrast.m_supported) { |
| attr.clear(); |
| attr["value"] = std::to_string(m_contrast.m_value); |
| os.openCloseChild("contrast", attr); |
| } |
| |
| if (m_threshold.m_supported) { |
| attr.clear(); |
| attr["value"] = std::to_string(m_threshold.m_value); |
| os.openCloseChild("threshold", attr); |
| } |
| } |
| |
| |
| |
| void TScannerParameters::loadData(TIStream &is) { |
| std::string tagName; |
| while (is.matchTag(tagName)) { |
| if (tagName == "dpi") { |
| std::string s = is.getTagAttribute("value"); |
| if (isDouble(s)) m_dpi.m_value = std::stof(s); |
| } else if (tagName == "brightness") { |
| std::string s = is.getTagAttribute("value"); |
| if (isDouble(s)) m_brightness.m_value = std::stof(s); |
| } else if (tagName == "threshold") { |
| std::string s = is.getTagAttribute("value"); |
| if (isDouble(s)) m_threshold.m_value = std::stof(s); |
| } else if (tagName == "contrast") { |
| std::string s = is.getTagAttribute("value"); |
| if (isDouble(s)) m_contrast.m_value = std::stof(s); |
| } else if (tagName == "autoFeeder") { |
| m_paperFeeder.m_value = 1.0; |
| } else if (tagName == "reverseOrder") { |
| m_reverseOrder = true; |
| } else if (tagName == "mode") { |
| std::string scanTypeString = is.getTagAttribute("value"); |
| m_scanType = None; |
| if (scanTypeString == BlackAndWhite) |
| m_scanType = BW; |
| else if (scanTypeString == Graytones) |
| m_scanType = GR8; |
| else if (scanTypeString == Rgbcolors) |
| m_scanType = RGB24; |
| } else if (tagName == "paper") { |
| std::string paperFormat = is.getTagAttribute("fmt"); |
| if (paperFormat != "") setPaperFormat(paperFormat); |
| } |
| } |
| m_validatedByCurrentScanner = false; |
| } |
| |
| |
| |
| |
| |
| |
| |
| namespace { |
| TScanner *instanceTwain = 0; |
| TScanner *instanceEpson = 0; |
| } |
| |
| |
| |
| bool TScanner::m_isTwain = true; |
| |
| |
| |
| namespace { |
| class Cleaner { |
| public: |
| bool m_activated; |
| Cleaner() : m_activated(false) {} |
| ~Cleaner() { |
| TScanner *scannerToDestroy = 0; |
| if (m_activated) scannerToDestroy = TScanner::instance(); |
| delete scannerToDestroy; |
| } |
| }; |
| Cleaner MyCleaner; |
| }; |
| |
| |
| |
| |
| #ifdef DUMMYSCAN |
| class TScannerDummy final : public TScanner { |
| public: |
| TScannerDummy() {} |
| ~TScannerDummy() {} |
| void selectDevice() {} |
| bool isDeviceAvailable() { return true; } |
| void updateParameters(TScannerParameters ¶meters) { |
| parameters.setSupportedTypes(false, true, true); |
| parameters.setMaxPaperSize(1000., 1000.); |
| parameters.enablePaperFeeder(true); |
| parameters.m_brightness.update(TScanParam(0, 255, 128, 1)); |
| parameters.m_contrast.update(TScanParam(0, 255, 128, 1)); |
| parameters.m_threshold.update(TScanParam(0, 255, 128, 1)); |
| parameters.m_dpi.update(TScanParam(60, 1200, 100, 1)); |
| |
| setName("DummyScanner"); |
| } |
| bool isTwain() const { return true; } |
| void acquire(const TScannerParameters ¶m, int paperCount) { return; } |
| bool isAreaSupported() { return true; } |
| }; |
| #endif |
| |
| |
| |
| TScanner *TScanner::instance() { |
| MyCleaner.m_activated = true; |
| #ifdef DUMMYSCAN |
| static TScannerDummy dummy = TScannerDummy(); |
| return &dummy; |
| #else |
| if (m_isTwain) { |
| if (instanceEpson) { |
| TScannerEpson *se = (TScannerEpson *)instanceEpson; |
| se->closeIO(); |
| |
| |
| } |
| if (!instanceTwain) instanceTwain = new TScannerTwain(); |
| } else if (!m_isTwain) { |
| if (instanceTwain) { |
| |
| |
| TTWAIN_CloseAll(0); |
| } |
| if (!instanceEpson) instanceEpson = new TScannerEpson(); |
| } |
| |
| return (m_isTwain ? instanceTwain : instanceEpson); |
| #endif |
| } |
| |
| |
| TScanner::TScanner() : m_paperLeft(0) {} |
| |
| |
| |
| TScanner::~TScanner() { |
| if (instanceEpson) { |
| TScannerEpson *se = (TScannerEpson *)instanceEpson; |
| se->closeIO(); |
| } |
| } |
| |
| |
| |
| void TScanner::addListener(TScannerListener *lst) { m_listeners.insert(lst); } |
| |
| |
| |
| void TScanner::removeListener(TScannerListener *lst) { m_listeners.erase(lst); } |
| |
| |
| |
| void TScanner::notifyImageDone(const TRasterImageP &img) { |
| std::set<TScannerListener *>::iterator it = m_listeners.begin(); |
| for (; it != m_listeners.end(); ++it) { |
| (*it)->onImage(img); |
| } |
| } |
| |
| |
| |
| void TScanner::notifyNextPaper() { |
| std::set<TScannerListener *>::iterator it = m_listeners.begin(); |
| for (; it != m_listeners.end(); ++it) { |
| (*it)->onNextPaper(); |
| } |
| } |
| |
| |
| |
| void TScanner::notifyAutomaticallyNextPaper() { |
| std::set<TScannerListener *>::iterator it = m_listeners.begin(); |
| for (; it != m_listeners.end(); ++it) { |
| (*it)->onAutomaticallyNextPaper(); |
| } |
| } |
| |
| |
| |
| void TScanner::notifyError() { |
| std::set<TScannerListener *>::iterator it = m_listeners.begin(); |
| for (; it != m_listeners.end(); ++it) { |
| (*it)->onError(); |
| } |
| } |
| |
| |
| |
| bool TScanner::isScanningCanceled() { |
| std::set<TScannerListener *>::iterator it = m_listeners.begin(); |
| for (; it != m_listeners.end(); ++it) { |
| if ((*it)->isCanceled()) return true; |
| } |
| return false; |
| } |
| |
| |
| |
| |
| |
| |
| |
| namespace { |
| const std::pair<std::string, TDimensionD> defaultPaperFormat( |
| "A4 paper", TDimensionD(210.00, 297.00)); |
| } |
| |
| |
| |
| TPaperFormatManager::TPaperFormatManager() { |
| readPaperFormats(); |
| |
| |
| if (!isValidFormat(defaultPaperFormat.first)) |
| m_formats[defaultPaperFormat.first] = Format(defaultPaperFormat.second); |
| } |
| |
| |
| |
| TPaperFormatManager *TPaperFormatManager::instance() { |
| static TPaperFormatManager _instance; |
| return &_instance; |
| } |
| |
| |
| |
| void TPaperFormatManager::getFormats(std::vector<std::string> &names) const { |
| for (FormatTable::const_iterator it = m_formats.begin(); |
| it != m_formats.end(); ++it) |
| names.push_back(it->first); |
| } |
| |
| |
| |
| TDimensionD TPaperFormatManager::getSize(std::string name) const { |
| FormatTable::const_iterator it = m_formats.find(name); |
| if (it == m_formats.end()) |
| return TDimensionD(0., 0.); |
| else |
| return it->second.m_size; |
| } |
| |
| |
| |
| bool TPaperFormatManager::isValidFormat(std::string name) const { |
| FormatTable::const_iterator it = m_formats.find(name); |
| return it != m_formats.end(); |
| } |
| |
| |
| |
| std::string TPaperFormatManager::getDefaultFormat() const { |
| return defaultPaperFormat.first; |
| } |
| |
| |
| |
| void TPaperFormatManager::readPaperFormat(const TFilePath &path) { |
| if (path.getType() != "pap") return; |
| Tifstream is(path); |
| std::string name; |
| TDimensionD size(0, 0); |
| while (is) { |
| char buffer[1024]; |
| is.getline(buffer, sizeof buffer); |
| |
| |
| unsigned int i = 0; |
| for (i = 0; i < sizeof buffer && buffer[i]; i++) { |
| } |
| if (i > 0 && buffer[i - 1] == '\n') i--; |
| while (i > 0 && buffer[i - 1] == ' ') i--; |
| unsigned int j = 0; |
| unsigned int k = 0; |
| |
| for (j = 0; j < i && buffer[j] != ' '; j++) { |
| } |
| |
| |
| for (k = j; k < i && buffer[k] == ' '; k++) { |
| } |
| |
| std::string value; |
| if (k < i) value = std::string(buffer + k, i - k); |
| |
| if (buffer[0] == '#') { |
| if (k < i && name == "") name = value; |
| } else if (std::string(buffer).find("WIDTH") == 0) { |
| if (isDouble(value)) size.lx = std::stod(value); |
| } else if (std::string(buffer).find("LENGTH") == 0) { |
| if (isDouble(value)) size.ly = std::stod(value); |
| } |
| } |
| if (name == "" || size.lx == 0 || size.ly == 0) { |
| |
| } else |
| m_formats[name] = Format(size); |
| } |
| |
| |
| |
| void TPaperFormatManager::readPaperFormats() { |
| TFilePathSet fps; |
| TFilePath papDir = TEnv::getConfigDir() + "pap"; |
| if (!TFileStatus(papDir).isDirectory()) { |
| |
| return; |
| } |
| |
| try { |
| fps = TSystem::readDirectory(papDir); |
| } catch (TException &) { |
| |
| return; |
| } |
| |
| TFilePathSet::const_iterator it = fps.begin(); |
| for (; it != fps.end(); ++it) readPaperFormat(*it); |
| } |
| |