2025-06-28 17:40:42 +02:00
|
|
|
/*
|
|
|
|
|
* File: InsaneWorker.cpp
|
|
|
|
|
* Author: Saleem Edah-Tally - nmset@yandex.com
|
|
|
|
|
* License : CeCILL-C
|
|
|
|
|
* Copyright Saleem Edah-Tally - © 2024
|
|
|
|
|
*
|
|
|
|
|
* Created on 14 02 2024, 13:00
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "InsaneWorker.h"
|
|
|
|
|
#include <iostream>
|
|
|
|
|
#include <iomanip>
|
|
|
|
|
#include <sstream>
|
|
|
|
|
#include <fstream>
|
|
|
|
|
#include <paper.h>
|
|
|
|
|
#include <libinsane/safebet.h>
|
|
|
|
|
#include <libinsane/error.h>
|
|
|
|
|
#include <libinsane/util.h>
|
|
|
|
|
#include <libinsane/normalizers.h>
|
|
|
|
|
#include <libinsane/constants.h>
|
|
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
|
|
|
|
|
#define IERR(e) ("[" + to_string(e) + "] " + lis_strerror(e))
|
|
|
|
|
static bool gs_cancelRequested = false;
|
|
|
|
|
|
|
|
|
|
InsaneWorker::InsaneWorker ( InsaneWorkerEvent * evh )
|
|
|
|
|
{
|
|
|
|
|
m_evh = evh;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
InsaneWorker::~InsaneWorker()
|
|
|
|
|
{
|
|
|
|
|
if (m_api)
|
|
|
|
|
m_api->cleanup(m_api);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool InsaneWorker::Init()
|
|
|
|
|
{
|
|
|
|
|
// Terminate a previous one.
|
|
|
|
|
if (m_api)
|
|
|
|
|
{
|
|
|
|
|
m_devices.clear();
|
|
|
|
|
m_deviceId.clear();
|
|
|
|
|
m_api->cleanup(m_api);
|
|
|
|
|
m_sourceItem = nullptr;
|
|
|
|
|
m_rootSourceItem = nullptr;
|
|
|
|
|
}
|
|
|
|
|
lis_error err;
|
|
|
|
|
err = lis_safebet ( &m_api );
|
|
|
|
|
if ( err )
|
|
|
|
|
{
|
|
|
|
|
if ( m_evh )
|
|
|
|
|
{
|
|
|
|
|
m_evh->OnInsaneError ( IERR(err) );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lis_device_descriptor ** devices = nullptr; // nullptr terminated.
|
|
|
|
|
err = m_api->list_devices ( m_api, LIS_DEVICE_LOCATIONS_LOCAL_ONLY, &devices ); // Gets network scanners though.
|
|
|
|
|
if ( err )
|
|
|
|
|
{
|
|
|
|
|
m_evh->OnInsaneError ( IERR(err) );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint numberOfDevices = 0;
|
|
|
|
|
for ( uint i = 0; devices[i] != nullptr; i++ )
|
|
|
|
|
{
|
|
|
|
|
numberOfDevices++;
|
|
|
|
|
}
|
|
|
|
|
// Collect available descriptions for all devices.
|
|
|
|
|
for ( uint i = 0; i < numberOfDevices; i++ )
|
|
|
|
|
{
|
|
|
|
|
DeviceDescriptor dd;
|
|
|
|
|
lis_device_descriptor * descriptor = devices[i];
|
|
|
|
|
dd.id = descriptor->dev_id;
|
|
|
|
|
dd.model = descriptor->model;
|
|
|
|
|
dd.type = descriptor->type;
|
|
|
|
|
dd.vendor = descriptor->vendor;
|
|
|
|
|
m_devices.push_back(dd);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Determine if a source item is a feeder.
|
|
|
|
|
int InsaneWorker::IsADF(const std::string& deviceId, int sourceChildIndex)
|
|
|
|
|
{
|
|
|
|
|
if ( !m_api )
|
|
|
|
|
{
|
|
|
|
|
if ( m_evh )
|
|
|
|
|
{
|
|
|
|
|
m_evh->OnError ( "Insane api is NULL; has Init() been called?");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
lis_error err;
|
|
|
|
|
lis_item * rootSourceItem = nullptr;
|
|
|
|
|
err = m_api->get_device ( m_api, deviceId.c_str(), &rootSourceItem );
|
|
|
|
|
if ( err )
|
|
|
|
|
{
|
|
|
|
|
if ( m_evh )
|
|
|
|
|
m_evh->OnInsaneError ( IERR ( err ) );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
lis_item ** children = nullptr;
|
|
|
|
|
err = rootSourceItem->get_children(rootSourceItem, &children);
|
|
|
|
|
if ( err )
|
|
|
|
|
{
|
|
|
|
|
if ( m_evh )
|
|
|
|
|
m_evh->OnInsaneError ( IERR ( err ) );
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool adf = (children[sourceChildIndex]->type == LIS_ITEM_ADF);
|
|
|
|
|
rootSourceItem->close(rootSourceItem);
|
|
|
|
|
return adf;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Ex: all supported resolutions.
|
|
|
|
|
std::string InsaneWorker::GetOptionPossibleValues(const std::string& deviceId,
|
|
|
|
|
const std::string& optionName, std::vector<std::string>& possible)
|
|
|
|
|
{
|
|
|
|
|
if ( !m_api )
|
|
|
|
|
{
|
|
|
|
|
if ( m_evh )
|
|
|
|
|
{
|
|
|
|
|
m_evh->OnError ( "Insane api is NULL; has Init() been called?");
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
lis_error err;
|
|
|
|
|
lis_item * item = nullptr;
|
|
|
|
|
err = m_api->get_device ( m_api, deviceId.c_str(), &item );
|
|
|
|
|
if ( err )
|
|
|
|
|
{
|
|
|
|
|
if ( m_evh )
|
|
|
|
|
m_evh->OnInsaneError ( IERR ( err ) );
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lis_option_descriptor ** options = nullptr;
|
|
|
|
|
err = item->get_options ( item, &options );
|
|
|
|
|
if ( err )
|
|
|
|
|
{
|
|
|
|
|
if ( m_evh )
|
|
|
|
|
m_evh->OnInsaneError ( IERR ( err ) );
|
|
|
|
|
item->close(item);
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
uint numberOfOptions = 0;
|
|
|
|
|
for ( uint i = 0; options[i] != nullptr; i++ )
|
|
|
|
|
{
|
|
|
|
|
numberOfOptions++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string defaultValue;
|
|
|
|
|
for ( uint i = 0; i < numberOfOptions; i++ )
|
|
|
|
|
{
|
|
|
|
|
lis_option_descriptor * optionDescriptor = options[i];
|
|
|
|
|
const std::string name = optionDescriptor->name;
|
|
|
|
|
if ( ToLower(name) != optionName )
|
|
|
|
|
continue;
|
|
|
|
|
union lis_value value;
|
|
|
|
|
err = optionDescriptor->fn.get_value ( optionDescriptor, &value );
|
|
|
|
|
if ( err )
|
|
|
|
|
{
|
|
|
|
|
if ( m_evh )
|
|
|
|
|
m_evh->OnInsaneError ( IERR ( err ) );
|
|
|
|
|
item->close(item);
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
lis_value_type type = optionDescriptor->value.type;
|
|
|
|
|
bool isString = false;
|
|
|
|
|
switch ( type )
|
|
|
|
|
{
|
|
|
|
|
case LIS_TYPE_BOOL:
|
|
|
|
|
defaultValue = std::to_string(( bool ) value.boolean);
|
|
|
|
|
break;
|
|
|
|
|
case LIS_TYPE_INTEGER:
|
|
|
|
|
defaultValue = std::to_string(( long ) value.integer);
|
|
|
|
|
break;
|
|
|
|
|
case LIS_TYPE_DOUBLE:
|
|
|
|
|
defaultValue = std::to_string(( double ) value.dbl);
|
|
|
|
|
break;
|
|
|
|
|
case LIS_TYPE_STRING:
|
|
|
|
|
isString = true;
|
|
|
|
|
defaultValue = value.string;
|
|
|
|
|
break;
|
|
|
|
|
case LIS_TYPE_IMAGE_FORMAT:
|
|
|
|
|
defaultValue = "Unmanaged";
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
defaultValue = "Unknown";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
lis_value_list valueList = optionDescriptor->constraint.possible.list;
|
|
|
|
|
int numberOfListItems = valueList.nb_values;
|
|
|
|
|
if ( numberOfListItems )
|
|
|
|
|
{
|
|
|
|
|
for ( int j = 0; j < numberOfListItems; j++ )
|
|
|
|
|
{
|
|
|
|
|
if ( isString )
|
|
|
|
|
possible.push_back( valueList.values[j].string );
|
|
|
|
|
else
|
|
|
|
|
possible.push_back( std::to_string ( valueList.values[j].integer ) );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
item->close(item);
|
|
|
|
|
return defaultValue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Open a source item and prepare for the next step, i.e, scanning.
|
|
|
|
|
bool InsaneWorker::ConfigureDevice(const std::string& deviceId,
|
|
|
|
|
const std::string& source, int sourceChildIndex,
|
|
|
|
|
const std::string& mode, int resolution,
|
|
|
|
|
const std::string& paperSize)
|
|
|
|
|
{
|
|
|
|
|
if ( !m_api )
|
|
|
|
|
{
|
|
|
|
|
if ( m_evh )
|
|
|
|
|
{
|
|
|
|
|
m_evh->OnError ( "Insane api is NULL; has Init() been called?");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
m_deviceId = deviceId;
|
|
|
|
|
m_source = source;
|
|
|
|
|
m_sourceChildIndex = (sourceChildIndex > -1) ? sourceChildIndex : 0;
|
|
|
|
|
m_mode = mode;
|
|
|
|
|
m_resolution = resolution;
|
|
|
|
|
m_paperSize = paperSize;
|
|
|
|
|
|
|
|
|
|
lis_error err;
|
|
|
|
|
|
|
|
|
|
err = m_api->get_device ( m_api, m_deviceId.c_str(), &m_rootSourceItem );
|
|
|
|
|
if ( err )
|
|
|
|
|
{
|
|
|
|
|
if ( m_evh )
|
|
|
|
|
m_evh->OnInsaneError ( IERR ( err ) );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lis_item ** children = nullptr;
|
|
|
|
|
err = m_rootSourceItem->get_children(m_rootSourceItem, &children);
|
|
|
|
|
if ( err )
|
|
|
|
|
{
|
|
|
|
|
if ( m_evh )
|
|
|
|
|
m_evh->OnInsaneError ( IERR ( err ) );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Selecting a lis_item by the source index.
|
|
|
|
|
// One child item is created by libinsane if there is no source: v4l.
|
|
|
|
|
m_sourceItem = children[m_sourceChildIndex];
|
|
|
|
|
if (!m_sourceItem)
|
|
|
|
|
{
|
|
|
|
|
if (m_evh)
|
|
|
|
|
m_evh->OnError("Could not determine a device item");
|
|
|
|
|
m_rootSourceItem->close(m_rootSourceItem);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Error status not checked; use defaults if failure.
|
|
|
|
|
lis_set_option(m_sourceItem, OPT_NAME_MODE, mode.c_str());
|
|
|
|
|
/*
|
|
|
|
|
* Selecting a source on a child item that has been selected by a source index.
|
|
|
|
|
* Sounds weird but needed.
|
|
|
|
|
*/
|
|
|
|
|
lis_set_option(m_sourceItem, OPT_NAME_SOURCE, source.c_str());
|
2025-07-01 22:38:07 +02:00
|
|
|
if (resolution > 0) // No resolution with v4l devices.
|
|
|
|
|
lis_set_option(m_sourceItem, OPT_NAME_RESOLUTION, to_string(resolution).c_str());
|
2025-06-28 17:40:42 +02:00
|
|
|
pair<double, double> br;
|
|
|
|
|
if (GetBottomRight(br))
|
|
|
|
|
{
|
|
|
|
|
// For v4l, these do not get applied.
|
|
|
|
|
lis_set_option(m_sourceItem, "br-x", to_string(br.first).c_str());
|
|
|
|
|
lis_set_option(m_sourceItem, "br-y", to_string(br.second).c_str());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Don't close m_rootDeviceItem, it is prepared for ::Scan().
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Perform scanning: create raw data files.
|
|
|
|
|
bool InsaneWorker::Scan(const std::string& dir, const std::string& basename,
|
|
|
|
|
int startIndex, int padwidth, int increment)
|
|
|
|
|
{
|
|
|
|
|
if ( !m_api || !m_sourceItem )
|
|
|
|
|
{
|
|
|
|
|
if ( m_evh )
|
|
|
|
|
{
|
|
|
|
|
m_evh->OnError ( "Insane api or device item is NULL, cannot scan.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (dir.empty() || basename.empty() || startIndex < 0 || padwidth < 0 || (increment == 0))
|
|
|
|
|
{
|
|
|
|
|
if ( m_evh )
|
|
|
|
|
{
|
|
|
|
|
m_evh->OnError ( "Invalid input, cannot scan.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
auto makeFileName = [&] (int index)
|
|
|
|
|
{
|
|
|
|
|
// std:format is not friendly with a variable padwidth; requires a literal format.
|
|
|
|
|
stringstream ss;
|
|
|
|
|
ss << setfill('0') << setw(padwidth) << index;
|
|
|
|
|
return (dir + "/" + basename + "-" + ss.str());
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
lis_error err;
|
|
|
|
|
|
|
|
|
|
lis_scan_session * session;
|
|
|
|
|
// Scanning starts here on device.
|
|
|
|
|
err = m_sourceItem->scan_start(m_sourceItem, &session);
|
|
|
|
|
if (err || !session)
|
|
|
|
|
{
|
|
|
|
|
if ( m_evh )
|
|
|
|
|
m_evh->OnInsaneError ( IERR ( err ) );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lis_scan_parameters parameters; // DO NOT use a POINTER here.
|
|
|
|
|
err = session->get_scan_parameters(session, ¶meters);
|
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
if ( m_evh )
|
|
|
|
|
m_evh->OnInsaneError ( IERR ( err ) );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* format is troublesome: always 0.
|
|
|
|
|
* But for LineArt, in the logs, sane_get_parameters() returns format=1 (v4l)
|
|
|
|
|
* or format=2 (remote).
|
|
|
|
|
*/
|
|
|
|
|
// lis_img_format format = parameters.format; // guaranteed, but always 0, even for LineArt.
|
|
|
|
|
const int lineArtFactor = (m_mode == string("LineArt") ? 3 : 1); // insane always outputs RGB.
|
|
|
|
|
int imageWidth = parameters.width; // pixels, guaranteed.
|
|
|
|
|
int imageHeight = parameters.height; // pixels, not guaranteed.
|
|
|
|
|
size_t imageSize = parameters.image_size * lineArtFactor; // bytes, not guaranteed.
|
|
|
|
|
InsaneWorkerEvent::ImageAttributes imageAttributes;
|
|
|
|
|
imageAttributes.size = imageSize;
|
|
|
|
|
imageAttributes.width = imageWidth;
|
|
|
|
|
imageAttributes.height = imageHeight;
|
|
|
|
|
|
|
|
|
|
// This file is valid raw pixels. It can be converted with rawtoppm and rawtopgm.
|
|
|
|
|
uint pageIndex = startIndex;
|
|
|
|
|
string filePath = makeFileName(pageIndex);
|
|
|
|
|
const int bytesPerRow = imageSize / imageHeight;
|
|
|
|
|
/*
|
|
|
|
|
* Needs confirmation.
|
|
|
|
|
* LineArt : 1 pixel = 1 bit - maximum resolution = 9600
|
|
|
|
|
* Gray : 1 pixel = 1 byte - maximum resolution = 2400
|
|
|
|
|
* Color : 1 pixel = 3 bytes - maximum resolution = 600
|
|
|
|
|
*
|
|
|
|
|
* A4, LineArt, 4800: 1690000620 bytes file OK (1.6 GiB).
|
|
|
|
|
* Above that resolution:
|
|
|
|
|
* std::bad_alloc - 1993034797 bytes (1.856 GiB) cannot be allocated
|
|
|
|
|
* for one row. System with 64 GB RAM.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (m_evh)
|
|
|
|
|
m_evh->OnStartScanSession(startIndex, imageAttributes);
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
ofstream outFile;
|
|
|
|
|
if (m_evh)
|
|
|
|
|
m_evh->OnPageStartScan(filePath, pageIndex, imageAttributes);
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
if (gs_cancelRequested)
|
|
|
|
|
{
|
|
|
|
|
session->cancel(session);
|
|
|
|
|
if (m_evh)
|
|
|
|
|
m_evh->OnSessionCancelled(filePath);
|
|
|
|
|
gs_cancelRequested = false;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
char * readBytes = new char[bytesPerRow];
|
|
|
|
|
size_t bufferSize = bytesPerRow;
|
|
|
|
|
err = session->scan_read(session, readBytes, &bufferSize); // bufferSize is in/out.
|
|
|
|
|
if (LIS_IS_ERROR(err))
|
|
|
|
|
{
|
|
|
|
|
delete[] readBytes;
|
|
|
|
|
if (m_evh)
|
|
|
|
|
m_evh->OnSessionReadError(filePath);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* bufferSize == 0 does not mean end_of_page or end of file.
|
|
|
|
|
* But we get here when end_of_feed is false while there's nothing more to read.
|
|
|
|
|
*/
|
|
|
|
|
if (bufferSize)
|
|
|
|
|
{
|
|
|
|
|
if (!outFile.is_open())
|
|
|
|
|
outFile.open(filePath, ios::binary | ios::trunc);
|
|
|
|
|
outFile.write((const char*) readBytes, bufferSize);
|
|
|
|
|
}
|
|
|
|
|
delete[] readBytes;
|
|
|
|
|
}
|
|
|
|
|
catch (std::bad_alloc& e)
|
|
|
|
|
{
|
|
|
|
|
m_rootSourceItem->close(m_rootSourceItem);
|
|
|
|
|
cout << "ABORT: " << e.what() << " - could not allocate " << bytesPerRow << " bytes." << endl;
|
|
|
|
|
if (m_evh)
|
|
|
|
|
m_evh->OnError("Insufficient system RAM.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
} while (!session->end_of_page(session));
|
|
|
|
|
/*
|
|
|
|
|
* end_of_feed may return false though there is no more to read.
|
|
|
|
|
* If outFile is not open, nothing was read; don't call OnPageEndScan.
|
|
|
|
|
*/
|
|
|
|
|
bool outFileWasOpen = outFile.is_open();
|
|
|
|
|
// It may not have been opened.
|
|
|
|
|
outFile.flush();
|
|
|
|
|
outFile.close();
|
|
|
|
|
if (m_evh && outFileWasOpen)
|
|
|
|
|
m_evh->OnPageEndScan(filePath, pageIndex, imageAttributes);
|
|
|
|
|
pageIndex += increment;
|
|
|
|
|
if (m_sourceItem->type != LIS_ITEM_ADF) // v4l also
|
|
|
|
|
break;
|
|
|
|
|
filePath = makeFileName(pageIndex);
|
|
|
|
|
} while( !session->end_of_feed(session));
|
|
|
|
|
if (m_evh)
|
|
|
|
|
m_evh->OnEndScanSession(pageIndex - increment, imageAttributes);
|
|
|
|
|
|
2025-07-01 17:48:21 +02:00
|
|
|
/*
|
|
|
|
|
* Don't close the child item.
|
|
|
|
|
* A v4l device may become unusable after the first capture (its child source
|
|
|
|
|
* item may have been faked by libinsane if it had none).
|
|
|
|
|
* Real scanners sustain both situations so far.
|
|
|
|
|
*/
|
2025-06-28 17:40:42 +02:00
|
|
|
m_rootSourceItem->close(m_rootSourceItem); // Root.
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Determine the page extent.
|
|
|
|
|
bool InsaneWorker::GetBottomRight(std::pair<double, double>& br)
|
|
|
|
|
{
|
|
|
|
|
int res = paperinit();
|
|
|
|
|
if (res != PAPER_OK)
|
|
|
|
|
{
|
|
|
|
|
const string msg = "Could not initialise the paper library.";
|
|
|
|
|
cerr << msg << endl;
|
|
|
|
|
if (m_evh)
|
|
|
|
|
m_evh->OnError(msg);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const paper * p = paperinfo(m_paperSize.c_str());
|
|
|
|
|
if (!p)
|
|
|
|
|
{
|
|
|
|
|
string msg = "Failed to find the requested paper; attempt to use a default paper size.";
|
|
|
|
|
cerr << msg << endl;
|
|
|
|
|
if (m_evh)
|
|
|
|
|
m_evh->OnError(msg);
|
|
|
|
|
p = defaultpaper();
|
|
|
|
|
if (!p)
|
|
|
|
|
{
|
|
|
|
|
msg = "Failed to find a default paper size; using the default scanner sizes.";
|
|
|
|
|
cerr << msg << endl;
|
|
|
|
|
if (m_evh)
|
|
|
|
|
m_evh->OnError(msg);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int unit = paperunit(p);
|
|
|
|
|
double conversionFactor = 1.0;
|
|
|
|
|
if (unit == PAPER_UNIT_MM)
|
|
|
|
|
conversionFactor = 1.0;
|
|
|
|
|
else if (unit == PAPER_UNIT_IN)
|
|
|
|
|
conversionFactor = 25.4;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
const string msg = "The measurement unit of the paper size is not handled; using the default scanner sizes.";
|
|
|
|
|
cerr << msg << endl;
|
|
|
|
|
if (m_evh)
|
|
|
|
|
m_evh->OnError(msg);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
br.first = paperwidth(p) * conversionFactor;
|
|
|
|
|
br.second = paperheight(p) * conversionFactor;
|
|
|
|
|
|
|
|
|
|
res = paperdone();
|
|
|
|
|
if (res != PAPER_OK)
|
|
|
|
|
{
|
|
|
|
|
const string msg = "Could not cleanly end the paper library.";
|
|
|
|
|
cerr << msg << endl;
|
|
|
|
|
if (m_evh)
|
|
|
|
|
m_evh->OnError(msg);
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::string InsaneWorker::ToLower(const std::string& input)
|
|
|
|
|
{
|
|
|
|
|
// We are dealing with single byte characters.
|
|
|
|
|
string output;
|
|
|
|
|
for ( char c : input )
|
|
|
|
|
output.append ( 1, std::tolower ( c ) );
|
|
|
|
|
return output;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InsaneWorker::Cancel()
|
|
|
|
|
{
|
|
|
|
|
gs_cancelRequested = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::pair<int, int> InsaneWorker::UpdateStartAndIncrement(const int startPageIndex, const int increment,
|
|
|
|
|
const bool adf, const bool doubleSided, const int total)
|
|
|
|
|
{
|
|
|
|
|
int newStartPageIndex = startPageIndex;
|
|
|
|
|
int newIncrement = increment;
|
|
|
|
|
int totalEven = total;
|
|
|
|
|
if (total % 2)
|
|
|
|
|
totalEven++;
|
|
|
|
|
// Scanning forward before max.
|
|
|
|
|
if ((increment > 0) && adf && doubleSided && (startPageIndex < (totalEven - 2)))
|
|
|
|
|
{
|
|
|
|
|
newIncrement = 2;
|
|
|
|
|
newStartPageIndex += newIncrement;
|
|
|
|
|
}
|
|
|
|
|
// Scanning forward at max.
|
|
|
|
|
else if ((increment > 0) && adf && doubleSided && (startPageIndex == (totalEven - 2)))
|
|
|
|
|
{
|
|
|
|
|
newIncrement = -2;
|
|
|
|
|
newStartPageIndex++;
|
|
|
|
|
}
|
|
|
|
|
// Scanning backward.
|
|
|
|
|
else if ((increment < 0) && adf && doubleSided && (startPageIndex <= (totalEven - 1)))
|
|
|
|
|
{
|
|
|
|
|
newIncrement = -2;
|
|
|
|
|
newStartPageIndex += newIncrement;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
newIncrement = 1;
|
|
|
|
|
newStartPageIndex++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::pair<int, int> result = {newStartPageIndex, newIncrement};
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
InsaneWorkerEvent::InsaneWorkerEvent()
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
InsaneWorkerEvent::~InsaneWorkerEvent()
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
void InsaneWorkerEvent::OnInsaneError ( const std::string& message )
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
void InsaneWorkerEvent::OnError ( const std::string& message )
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
void InsaneWorkerEvent::OnSessionCancelled(const std::string& filePath)
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
void InsaneWorkerEvent::OnSessionReadError(const std::string& filePath)
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
void InsaneWorkerEvent::OnPageStartScan(const std::string& filePath,uint pageIndex, const ImageAttributes& imageAttributes)
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
void InsaneWorkerEvent::OnPageEndScan(const std::string& filePath, uint pageIndex, const ImageAttributes& imageAttributes)
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
void InsaneWorkerEvent::OnStartScanSession(uint pageIndex, const ImageAttributes& imageAttributes)
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
void InsaneWorkerEvent::OnEndScanSession(uint pageIndex, const ImageAttributes& imageAttributes)
|
|
|
|
|
{}
|