#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"
}
//===================================================================
//
// TScanParam
//
//-------------------------------------------------------------------
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);
}
//===================================================================
//
// TScannerParameters
//
//-------------------------------------------------------------------
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) {
// probabilmente non e' ancora stato selezionato uno scanner e quindi non e'
// definita una maxPaperSize
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)
{
// assert(maxWidth>0 && maxHeight>0);
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 &) {
//TMessage::error("%1", e.getMessage());
}
}
//-------------------------------------------------------------------------------------------------
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;
}
//===================================================================
//
// TScanner
//
//-------------------------------------------------------------------
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;
};
//-------------------------------------------------------------------
// #define DUMMYSCAN
#ifdef DUMMYSCAN
class TScannerDummy : 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();
//delete m_instanceEpson; //e' singletone, perche' buttarlo? (vinz)
//m_instanceEpson=0;
}
if (!instanceTwain)
instanceTwain = new TScannerTwain();
} else if (!m_isTwain) {
if (instanceTwain) {
//delete m_instanceTwain; //e' singletone, perche' buttarlo? (vinz)
//m_instanceTwain=0;
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();
}
}
//-----------------------------------------------------------------------------
/*! If one listener is set to cancel return true. */
bool TScanner::isScanningCanceled()
{
std::set<TScannerListener *>::iterator it = m_listeners.begin();
for (; it != m_listeners.end(); ++it) {
if ((*it)->isCanceled())
return true;
}
return false;
}
//===================================================================
//
// TPaperFormatManager
//
//-------------------------------------------------------------------
namespace
{
const std::pair<std::string, TDimensionD> defaultPaperFormat("A4 paper", TDimensionD(210.00, 297.00));
}
//-----------------------------------------------------------------------------
TPaperFormatManager::TPaperFormatManager()
{
readPaperFormats();
// se non c'e' aggiungo il formato di default. In questo modo e' sempre definito
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);
// i e' il carattere successivo alla fine della linea
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;
// j e' il carattere successivo alla fine del primo token
for (j = 0; j < i && buffer[j] != ' '; j++) {
}
// k e' l'inizio del secondo token (se c'e', altrimenti == i)
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) {
// TMessage::error("Error reading paper format file : %1",path);
} else
m_formats[name] = Format(size);
}
//-----------------------------------------------------------------------------
void TPaperFormatManager::readPaperFormats()
{
TFilePathSet fps;
TFilePath papDir = TEnv::getConfigDir() + "pap";
if (!TFileStatus(papDir).isDirectory()) {
// TMessage::error("E_CanNotReadDirectory_%1", papDir);
return;
}
try {
fps = TSystem::readDirectory(papDir);
} catch (TException &) {
// TMessage::error("E_CanNotReadDirectory_%1", papDir);
return;
}
TFilePathSet::const_iterator it = fps.begin();
for (; it != fps.end(); ++it)
readPaperFormat(*it);
}