Compare commits

..

No commits in common. "master" and "2.0.2" have entirely different histories.

218 changed files with 11875 additions and 50543 deletions

45
.appveyor.yml Normal file
View File

@ -0,0 +1,45 @@
image: Visual Studio 2015
environment:
ARCH: x86
sf_secret:
secure: 8QOHSPQLI/lmjgOhyGOsMA5MxOdeSnlFWWKjntqEfBMfW/XCuiEk5tHNjZiiAw8N
sf_api:
secure: S4qrbAdLq3Hw5yozC7XAavTGzpPPh8MleX+r8kaueBtPZUeJGt+8EoqaPw0P1PzV
clone_depth: 10
platform:
- x64
init:
- if /i %APPVEYOR_REPO_TAG% == true set WITH_TESSDATA=1
cache:
- installed -> scripts\win\prepare.bat
install:
- cinst winscp
- nuget install secure-file -ExcludeVersion
- call "scripts\win\prepare.bat"
build_script:
- call "scripts\win\build.bat"
artifacts:
- path: 'screen-translator-*.exe'
name: installer
deploy:
- provider: GitHub
description: "Version $(APPVEYOR_REPO_TAG_NAME)"
auth_token:
secure: NnyUV44yNAx8ea1L46dVhE4kQxUGd5M1O+yVk+9ncsNHWtw/9JoCnDqNybnxTccP
artifact: installer
force_update: true
on:
appveyor_repo_tag: true
after_deploy:
- secure-file\tools\secure-file -decrypt scripts\win\sf_key.av -secret %sf_secret% -out scripts\win\sf_key
- call "scripts\win\deploy_sf.bat"

View File

@ -1,16 +0,0 @@
---
BasedOnStyle: Google
AccessModifierOffset: '-2'
AllowShortCaseLabelsOnASingleLine: 'true'
AllowShortFunctionsOnASingleLine: InlineOnly
AllowShortIfStatementsOnASingleLine: 'false'
BreakBeforeBraces: Linux
BreakConstructorInitializers: BeforeComma
ConstructorInitializerAllOnOneLineOrOnePerLine: 'false'
ConstructorInitializerIndentWidth: '2'
Standard: Cpp11
TabWidth: '2'
UseTab: Never
IncludeBlocks: Preserve
...

View File

@ -1,37 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: 'bug'
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Logs**
Application log file recorded during an error.
To start recording a log file, open the settings window,
enable the 'write trace file' option and apply the settings.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. windows 10, ubuntu 18.04]
- Desktop environment (linux only): [e.g. KDE, Gnome]
- App version (release archive name): [e.g. 3.0.0-win32, 3.0.0-compatible-win64]
**Additional context**
Add any other context about the problem here.

View File

@ -1,20 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: 'enhancement'
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@ -1,100 +0,0 @@
name: App build
on: [push]
jobs:
release:
name: Create release
if: contains(github.ref, '/tags/')
runs-on: ubuntu-18.04
steps:
- name: Create release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: ${{ github.ref }}
draft: false
prerelease: false
- name: Store release url
run: echo "${{ steps.create_release.outputs.upload_url }}" > ./release_upload_url
- name: Upload release url
uses: actions/upload-artifact@v1
with:
path: ./release_upload_url
name: release_upload_url
build:
name: Build ${{ matrix.config.name }}${{ matrix.config.tag }}
runs-on: ${{ matrix.config.os }}
env:
OS: ${{ matrix.config.name }}
MSVC_VERSION: C:/Program Files/Microsoft Visual Studio/2022/Enterprise
strategy:
matrix:
config:
- { name: "win64", os: windows-latest }
- { name: "win32", os: windows-latest }
- { name: "linux", os: ubuntu-18.04 }
# - { name: "macos", os: macos-latest }
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 10
- name: Setup python
uses: actions/setup-python@v1
with:
python-version: "3.x"
- name: Install system libs
if: runner.os == 'Linux'
run: |
sudo apt-get install libgl1-mesa-dev libxkbcommon-x11-0 libxcb-*
echo "QMAKE_FLAGS=QMAKE_CXX=g++-10 QMAKE_CC=gcc-10 QMAKE_LINK=g++-10" >> $GITHUB_ENV
- name: Cache dependencies
uses: actions/cache@v2
with:
path: deps
key: ${{ env.OS }}-${{ hashFiles('./share/ci/*.py') }}
- name: Make a release
shell: bash
run: |
python ./share/ci/release.py
echo "artifact=`python ./share/ci/release.py artifact_name`" >> $GITHUB_ENV
- name: Upload build artifact
if: env.artifact != ''
uses: actions/upload-artifact@v1
with:
name: ${{ env.artifact }}
path: ./${{ env.artifact }}
- name: Download release url
if: contains(github.ref, '/tags/')
uses: actions/download-artifact@v4.1.7
with:
name: release_upload_url
path: ./
- name: Set release env
if: contains(github.ref, '/tags/')
shell: bash
run: echo "upload_url=`cat ./release_upload_url`" >> $GITHUB_ENV
- name: Upload release artifacts
if: contains(github.ref, '/tags/')
uses: actions/upload-release-asset@v1.0.1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ env.upload_url }}
asset_path: ./${{ env.artifact }}
asset_name: ${{ env.artifact }}
asset_content_type: application/zip

1
.gitignore vendored
View File

@ -8,4 +8,3 @@
distr/content/
*.tar.gz
__pycache__

20
.travis.yml Normal file
View File

@ -0,0 +1,20 @@
language: cpp
compiler:
- gcc
- clang
sudo: required
dist: trusty
install: ./scripts/install_deps.sh
script: cd scripts && ./make_all.sh
branches:
only:
- master
- develop
- /release.*/
- /.*travis/
os:
- linux
notifications:
email:
on_success: change
on_failure: change

View File

@ -0,0 +1,204 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qtlocalpeer.h"
#include <QCoreApplication>
#include <QDataStream>
#include <QTime>
#if defined(Q_OS_WIN)
#include <QLibrary>
#include <qt_windows.h>
typedef BOOL(WINAPI*PProcessIdToSessionId)(DWORD,DWORD*);
static PProcessIdToSessionId pProcessIdToSessionId = 0;
#endif
#if defined(Q_OS_UNIX)
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#endif
namespace QtLP_Private {
#include "qtlockedfile.cpp"
#if defined(Q_OS_WIN)
#include "qtlockedfile_win.cpp"
#else
#include "qtlockedfile_unix.cpp"
#endif
}
const char* QtLocalPeer::ack = "ack";
QtLocalPeer::QtLocalPeer(QObject* parent, const QString &appId)
: QObject(parent), id(appId)
{
QString prefix = id;
if (id.isEmpty()) {
id = QCoreApplication::applicationFilePath();
#if defined(Q_OS_WIN)
id = id.toLower();
#endif
prefix = id.section(QLatin1Char('/'), -1);
}
prefix.remove(QRegExp("[^a-zA-Z]"));
prefix.truncate(6);
QByteArray idc = id.toUtf8();
quint16 idNum = qChecksum(idc.constData(), idc.size());
socketName = QLatin1String("qtsingleapp-") + prefix
+ QLatin1Char('-') + QString::number(idNum, 16);
#if defined(Q_OS_WIN)
if (!pProcessIdToSessionId) {
QLibrary lib("kernel32");
pProcessIdToSessionId = (PProcessIdToSessionId)lib.resolve("ProcessIdToSessionId");
}
if (pProcessIdToSessionId) {
DWORD sessionId = 0;
pProcessIdToSessionId(GetCurrentProcessId(), &sessionId);
socketName += QLatin1Char('-') + QString::number(sessionId, 16);
}
#else
socketName += QLatin1Char('-') + QString::number(::getuid(), 16);
#endif
server = new QLocalServer(this);
QString lockName = QDir(QDir::tempPath()).absolutePath()
+ QLatin1Char('/') + socketName
+ QLatin1String("-lockfile");
lockFile.setFileName(lockName);
lockFile.open(QIODevice::ReadWrite);
}
bool QtLocalPeer::isClient()
{
if (lockFile.isLocked())
return false;
if (!lockFile.lock(QtLP_Private::QtLockedFile::WriteLock, false))
return true;
bool res = server->listen(socketName);
#if defined(Q_OS_UNIX) && (QT_VERSION >= QT_VERSION_CHECK(4,5,0))
// ### Workaround
if (!res && server->serverError() == QAbstractSocket::AddressInUseError) {
QFile::remove(QDir::cleanPath(QDir::tempPath())+QLatin1Char('/')+socketName);
res = server->listen(socketName);
}
#endif
if (!res)
qWarning("QtSingleCoreApplication: listen on local socket failed, %s", qPrintable(server->errorString()));
QObject::connect(server, SIGNAL(newConnection()), SLOT(receiveConnection()));
return false;
}
bool QtLocalPeer::sendMessage(const QString &message, int timeout)
{
if (!isClient())
return false;
QLocalSocket socket;
bool connOk = false;
for(int i = 0; i < 2; i++) {
// Try twice, in case the other instance is just starting up
socket.connectToServer(socketName);
connOk = socket.waitForConnected(timeout/2);
if (connOk || i)
break;
int ms = 250;
#if defined(Q_OS_WIN)
Sleep(DWORD(ms));
#else
struct timespec ts = { ms / 1000, (ms % 1000) * 1000 * 1000 };
nanosleep(&ts, NULL);
#endif
}
if (!connOk)
return false;
QByteArray uMsg(message.toUtf8());
QDataStream ds(&socket);
ds.writeBytes(uMsg.constData(), uMsg.size());
bool res = socket.waitForBytesWritten(timeout);
if (res) {
res &= socket.waitForReadyRead(timeout); // wait for ack
if (res)
res &= (socket.read(qstrlen(ack)) == ack);
}
return res;
}
void QtLocalPeer::receiveConnection()
{
QLocalSocket* socket = server->nextPendingConnection();
if (!socket)
return;
while (socket->bytesAvailable() < (int)sizeof(quint32))
socket->waitForReadyRead();
QDataStream ds(socket);
QByteArray uMsg;
quint32 remaining;
ds >> remaining;
uMsg.resize(remaining);
int got = 0;
char* uMsgBuf = uMsg.data();
do {
got = ds.readRawData(uMsgBuf, remaining);
remaining -= got;
uMsgBuf += got;
} while (remaining && got >= 0 && socket->waitForReadyRead(2000));
if (got < 0) {
qWarning("QtLocalPeer: Message reception failed %s", socket->errorString().toLatin1().constData());
delete socket;
return;
}
QString message(QString::fromUtf8(uMsg));
socket->write(ack, qstrlen(ack));
socket->waitForBytesWritten(1000);
socket->waitForDisconnected(1000); // make sure client reads ack
delete socket;
emit messageReceived(message); //### (might take a long time to return)
}

View File

@ -0,0 +1,77 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QTLOCALPEER_H
#define QTLOCALPEER_H
#include <QLocalServer>
#include <QLocalSocket>
#include <QDir>
#include "qtlockedfile.h"
class QtLocalPeer : public QObject
{
Q_OBJECT
public:
QtLocalPeer(QObject *parent = 0, const QString &appId = QString());
bool isClient();
bool sendMessage(const QString &message, int timeout);
QString applicationId() const
{ return id; }
Q_SIGNALS:
void messageReceived(const QString &message);
protected Q_SLOTS:
void receiveConnection();
protected:
QString id;
QString socketName;
QLocalServer* server;
QtLP_Private::QtLockedFile lockFile;
private:
static const char* ack;
};
#endif // QTLOCALPEER_H

View File

@ -0,0 +1,193 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qtlockedfile.h"
/*!
\class QtLockedFile
\brief The QtLockedFile class extends QFile with advisory locking
functions.
A file may be locked in read or write mode. Multiple instances of
\e QtLockedFile, created in multiple processes running on the same
machine, may have a file locked in read mode. Exactly one instance
may have it locked in write mode. A read and a write lock cannot
exist simultaneously on the same file.
The file locks are advisory. This means that nothing prevents
another process from manipulating a locked file using QFile or
file system functions offered by the OS. Serialization is only
guaranteed if all processes that access the file use
QLockedFile. Also, while holding a lock on a file, a process
must not open the same file again (through any API), or locks
can be unexpectedly lost.
The lock provided by an instance of \e QtLockedFile is released
whenever the program terminates. This is true even when the
program crashes and no destructors are called.
*/
/*! \enum QtLockedFile::LockMode
This enum describes the available lock modes.
\value ReadLock A read lock.
\value WriteLock A write lock.
\value NoLock Neither a read lock nor a write lock.
*/
/*!
Constructs an unlocked \e QtLockedFile object. This constructor
behaves in the same way as \e QFile::QFile().
\sa QFile::QFile()
*/
QtLockedFile::QtLockedFile()
: QFile()
{
#ifdef Q_OS_WIN
wmutex = 0;
rmutex = 0;
#endif
m_lock_mode = NoLock;
}
/*!
Constructs an unlocked QtLockedFile object with file \a name. This
constructor behaves in the same way as \e QFile::QFile(const
QString&).
\sa QFile::QFile()
*/
QtLockedFile::QtLockedFile(const QString &name)
: QFile(name)
{
#ifdef Q_OS_WIN
wmutex = 0;
rmutex = 0;
#endif
m_lock_mode = NoLock;
}
/*!
Opens the file in OpenMode \a mode.
This is identical to QFile::open(), with the one exception that the
Truncate mode flag is disallowed. Truncation would conflict with the
advisory file locking, since the file would be modified before the
write lock is obtained. If truncation is required, use resize(0)
after obtaining the write lock.
Returns true if successful; otherwise false.
\sa QFile::open(), QFile::resize()
*/
bool QtLockedFile::open(OpenMode mode)
{
if (mode & QIODevice::Truncate) {
qWarning("QtLockedFile::open(): Truncate mode not allowed.");
return false;
}
return QFile::open(mode);
}
/*!
Returns \e true if this object has a in read or write lock;
otherwise returns \e false.
\sa lockMode()
*/
bool QtLockedFile::isLocked() const
{
return m_lock_mode != NoLock;
}
/*!
Returns the type of lock currently held by this object, or \e
QtLockedFile::NoLock.
\sa isLocked()
*/
QtLockedFile::LockMode QtLockedFile::lockMode() const
{
return m_lock_mode;
}
/*!
\fn bool QtLockedFile::lock(LockMode mode, bool block = true)
Obtains a lock of type \a mode. The file must be opened before it
can be locked.
If \a block is true, this function will block until the lock is
aquired. If \a block is false, this function returns \e false
immediately if the lock cannot be aquired.
If this object already has a lock of type \a mode, this function
returns \e true immediately. If this object has a lock of a
different type than \a mode, the lock is first released and then a
new lock is obtained.
This function returns \e true if, after it executes, the file is
locked by this object, and \e false otherwise.
\sa unlock(), isLocked(), lockMode()
*/
/*!
\fn bool QtLockedFile::unlock()
Releases a lock.
If the object has no lock, this function returns immediately.
This function returns \e true if, after it executes, the file is
not locked by this object, and \e false otherwise.
\sa lock(), isLocked(), lockMode()
*/
/*!
\fn QtLockedFile::~QtLockedFile()
Destroys the \e QtLockedFile object. If any locks were held, they
are released.
*/

View File

@ -0,0 +1,97 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QTLOCKEDFILE_H
#define QTLOCKEDFILE_H
#include <QFile>
#ifdef Q_OS_WIN
#include <QVector>
#endif
#if defined(Q_OS_WIN)
# if !defined(QT_QTLOCKEDFILE_EXPORT) && !defined(QT_QTLOCKEDFILE_IMPORT)
# define QT_QTLOCKEDFILE_EXPORT
# elif defined(QT_QTLOCKEDFILE_IMPORT)
# if defined(QT_QTLOCKEDFILE_EXPORT)
# undef QT_QTLOCKEDFILE_EXPORT
# endif
# define QT_QTLOCKEDFILE_EXPORT __declspec(dllimport)
# elif defined(QT_QTLOCKEDFILE_EXPORT)
# undef QT_QTLOCKEDFILE_EXPORT
# define QT_QTLOCKEDFILE_EXPORT __declspec(dllexport)
# endif
#else
# define QT_QTLOCKEDFILE_EXPORT
#endif
namespace QtLP_Private {
class QT_QTLOCKEDFILE_EXPORT QtLockedFile : public QFile
{
public:
enum LockMode { NoLock = 0, ReadLock, WriteLock };
QtLockedFile();
QtLockedFile(const QString &name);
~QtLockedFile();
bool open(OpenMode mode);
bool lock(LockMode mode, bool block = true);
bool unlock();
bool isLocked() const;
LockMode lockMode() const;
private:
#ifdef Q_OS_WIN
Qt::HANDLE wmutex;
Qt::HANDLE rmutex;
QVector<Qt::HANDLE> rmutexes;
QString mutexname;
Qt::HANDLE getMutexHandle(int idx, bool doCreate);
bool waitMutex(Qt::HANDLE mutex, bool doBlock);
#endif
LockMode m_lock_mode;
};
}
#endif

View File

@ -0,0 +1,115 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include "qtlockedfile.h"
bool QtLockedFile::lock(LockMode mode, bool block)
{
if (!isOpen()) {
qWarning("QtLockedFile::lock(): file is not opened");
return false;
}
if (mode == NoLock)
return unlock();
if (mode == m_lock_mode)
return true;
if (m_lock_mode != NoLock)
unlock();
struct flock fl;
fl.l_whence = SEEK_SET;
fl.l_start = 0;
fl.l_len = 0;
fl.l_type = (mode == ReadLock) ? F_RDLCK : F_WRLCK;
int cmd = block ? F_SETLKW : F_SETLK;
int ret = fcntl(handle(), cmd, &fl);
if (ret == -1) {
if (errno != EINTR && errno != EAGAIN)
qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno));
return false;
}
m_lock_mode = mode;
return true;
}
bool QtLockedFile::unlock()
{
if (!isOpen()) {
qWarning("QtLockedFile::unlock(): file is not opened");
return false;
}
if (!isLocked())
return true;
struct flock fl;
fl.l_whence = SEEK_SET;
fl.l_start = 0;
fl.l_len = 0;
fl.l_type = F_UNLCK;
int ret = fcntl(handle(), F_SETLKW, &fl);
if (ret == -1) {
qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno));
return false;
}
m_lock_mode = NoLock;
return true;
}
QtLockedFile::~QtLockedFile()
{
if (isOpen())
unlock();
}

View File

@ -0,0 +1,211 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qtlockedfile.h"
#include <qt_windows.h>
#include <QFileInfo>
#define MUTEX_PREFIX "QtLockedFile mutex "
// Maximum number of concurrent read locks. Must not be greater than MAXIMUM_WAIT_OBJECTS
#define MAX_READERS MAXIMUM_WAIT_OBJECTS
#if QT_VERSION >= 0x050000
#define QT_WA(unicode, ansi) unicode
#endif
Qt::HANDLE QtLockedFile::getMutexHandle(int idx, bool doCreate)
{
if (mutexname.isEmpty()) {
QFileInfo fi(*this);
mutexname = QString::fromLatin1(MUTEX_PREFIX)
+ fi.absoluteFilePath().toLower();
}
QString mname(mutexname);
if (idx >= 0)
mname += QString::number(idx);
Qt::HANDLE mutex;
if (doCreate) {
QT_WA( { mutex = CreateMutexW(NULL, FALSE, (TCHAR*)mname.utf16()); },
{ mutex = CreateMutexA(NULL, FALSE, mname.toLocal8Bit().constData()); } );
if (!mutex) {
qErrnoWarning("QtLockedFile::lock(): CreateMutex failed");
return 0;
}
}
else {
QT_WA( { mutex = OpenMutexW(SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, (TCHAR*)mname.utf16()); },
{ mutex = OpenMutexA(SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, mname.toLocal8Bit().constData()); } );
if (!mutex) {
if (GetLastError() != ERROR_FILE_NOT_FOUND)
qErrnoWarning("QtLockedFile::lock(): OpenMutex failed");
return 0;
}
}
return mutex;
}
bool QtLockedFile::waitMutex(Qt::HANDLE mutex, bool doBlock)
{
Q_ASSERT(mutex);
DWORD res = WaitForSingleObject(mutex, doBlock ? INFINITE : 0);
switch (res) {
case WAIT_OBJECT_0:
case WAIT_ABANDONED:
return true;
break;
case WAIT_TIMEOUT:
break;
default:
qErrnoWarning("QtLockedFile::lock(): WaitForSingleObject failed");
}
return false;
}
bool QtLockedFile::lock(LockMode mode, bool block)
{
if (!isOpen()) {
qWarning("QtLockedFile::lock(): file is not opened");
return false;
}
if (mode == NoLock)
return unlock();
if (mode == m_lock_mode)
return true;
if (m_lock_mode != NoLock)
unlock();
if (!wmutex && !(wmutex = getMutexHandle(-1, true)))
return false;
if (!waitMutex(wmutex, block))
return false;
if (mode == ReadLock) {
int idx = 0;
for (; idx < MAX_READERS; idx++) {
rmutex = getMutexHandle(idx, false);
if (!rmutex || waitMutex(rmutex, false))
break;
CloseHandle(rmutex);
}
bool ok = true;
if (idx >= MAX_READERS) {
qWarning("QtLockedFile::lock(): too many readers");
rmutex = 0;
ok = false;
}
else if (!rmutex) {
rmutex = getMutexHandle(idx, true);
if (!rmutex || !waitMutex(rmutex, false))
ok = false;
}
if (!ok && rmutex) {
CloseHandle(rmutex);
rmutex = 0;
}
ReleaseMutex(wmutex);
if (!ok)
return false;
}
else {
Q_ASSERT(rmutexes.isEmpty());
for (int i = 0; i < MAX_READERS; i++) {
Qt::HANDLE mutex = getMutexHandle(i, false);
if (mutex)
rmutexes.append(mutex);
}
if (rmutexes.size()) {
DWORD res = WaitForMultipleObjects(rmutexes.size(), rmutexes.constData(),
TRUE, block ? INFINITE : 0);
if (res != WAIT_OBJECT_0 && res != WAIT_ABANDONED) {
if (res != WAIT_TIMEOUT)
qErrnoWarning("QtLockedFile::lock(): WaitForMultipleObjects failed");
m_lock_mode = WriteLock; // trick unlock() to clean up - semiyucky
unlock();
return false;
}
}
}
m_lock_mode = mode;
return true;
}
bool QtLockedFile::unlock()
{
if (!isOpen()) {
qWarning("QtLockedFile::unlock(): file is not opened");
return false;
}
if (!isLocked())
return true;
if (m_lock_mode == ReadLock) {
ReleaseMutex(rmutex);
CloseHandle(rmutex);
rmutex = 0;
}
else {
foreach(Qt::HANDLE mutex, rmutexes) {
ReleaseMutex(mutex);
CloseHandle(mutex);
}
rmutexes.clear();
ReleaseMutex(wmutex);
}
m_lock_mode = QtLockedFile::NoLock;
return true;
}
QtLockedFile::~QtLockedFile()
{
if (isOpen())
unlock();
if (wmutex)
CloseHandle(wmutex);
}

View File

@ -0,0 +1,347 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qtsingleapplication.h"
#include "qtlocalpeer.h"
#include <QWidget>
/*!
\class QtSingleApplication qtsingleapplication.h
\brief The QtSingleApplication class provides an API to detect and
communicate with running instances of an application.
This class allows you to create applications where only one
instance should be running at a time. I.e., if the user tries to
launch another instance, the already running instance will be
activated instead. Another usecase is a client-server system,
where the first started instance will assume the role of server,
and the later instances will act as clients of that server.
By default, the full path of the executable file is used to
determine whether two processes are instances of the same
application. You can also provide an explicit identifier string
that will be compared instead.
The application should create the QtSingleApplication object early
in the startup phase, and call isRunning() to find out if another
instance of this application is already running. If isRunning()
returns false, it means that no other instance is running, and
this instance has assumed the role as the running instance. In
this case, the application should continue with the initialization
of the application user interface before entering the event loop
with exec(), as normal.
The messageReceived() signal will be emitted when the running
application receives messages from another instance of the same
application. When a message is received it might be helpful to the
user to raise the application so that it becomes visible. To
facilitate this, QtSingleApplication provides the
setActivationWindow() function and the activateWindow() slot.
If isRunning() returns true, another instance is already
running. It may be alerted to the fact that another instance has
started by using the sendMessage() function. Also data such as
startup parameters (e.g. the name of the file the user wanted this
new instance to open) can be passed to the running instance with
this function. Then, the application should terminate (or enter
client mode).
If isRunning() returns true, but sendMessage() fails, that is an
indication that the running instance is frozen.
Here's an example that shows how to convert an existing
application to use QtSingleApplication. It is very simple and does
not make use of all QtSingleApplication's functionality (see the
examples for that).
\code
// Original
int main(int argc, char **argv)
{
QApplication app(argc, argv);
MyMainWidget mmw;
mmw.show();
return app.exec();
}
// Single instance
int main(int argc, char **argv)
{
QtSingleApplication app(argc, argv);
if (app.isRunning())
return !app.sendMessage(someDataString);
MyMainWidget mmw;
app.setActivationWindow(&mmw);
mmw.show();
return app.exec();
}
\endcode
Once this QtSingleApplication instance is destroyed (normally when
the process exits or crashes), when the user next attempts to run the
application this instance will not, of course, be encountered. The
next instance to call isRunning() or sendMessage() will assume the
role as the new running instance.
For console (non-GUI) applications, QtSingleCoreApplication may be
used instead of this class, to avoid the dependency on the QtGui
library.
\sa QtSingleCoreApplication
*/
void QtSingleApplication::sysInit(const QString &appId)
{
actWin = 0;
peer = new QtLocalPeer(this, appId);
connect(peer, SIGNAL(messageReceived(const QString&)), SIGNAL(messageReceived(const QString&)));
}
/*!
Creates a QtSingleApplication object. The application identifier
will be QCoreApplication::applicationFilePath(). \a argc, \a
argv, and \a GUIenabled are passed on to the QAppliation constructor.
If you are creating a console application (i.e. setting \a
GUIenabled to false), you may consider using
QtSingleCoreApplication instead.
*/
QtSingleApplication::QtSingleApplication(int &argc, char **argv, bool GUIenabled)
: QApplication(argc, argv, GUIenabled)
{
sysInit();
}
/*!
Creates a QtSingleApplication object with the application
identifier \a appId. \a argc and \a argv are passed on to the
QAppliation constructor.
*/
QtSingleApplication::QtSingleApplication(const QString &appId, int &argc, char **argv)
: QApplication(argc, argv)
{
sysInit(appId);
}
#if QT_VERSION < 0x050000
/*!
Creates a QtSingleApplication object. The application identifier
will be QCoreApplication::applicationFilePath(). \a argc, \a
argv, and \a type are passed on to the QAppliation constructor.
*/
QtSingleApplication::QtSingleApplication(int &argc, char **argv, Type type)
: QApplication(argc, argv, type)
{
sysInit();
}
# if defined(Q_WS_X11)
/*!
Special constructor for X11, ref. the documentation of
QApplication's corresponding constructor. The application identifier
will be QCoreApplication::applicationFilePath(). \a dpy, \a visual,
and \a cmap are passed on to the QApplication constructor.
*/
QtSingleApplication::QtSingleApplication(Display* dpy, Qt::HANDLE visual, Qt::HANDLE cmap)
: QApplication(dpy, visual, cmap)
{
sysInit();
}
/*!
Special constructor for X11, ref. the documentation of
QApplication's corresponding constructor. The application identifier
will be QCoreApplication::applicationFilePath(). \a dpy, \a argc, \a
argv, \a visual, and \a cmap are passed on to the QApplication
constructor.
*/
QtSingleApplication::QtSingleApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual, Qt::HANDLE cmap)
: QApplication(dpy, argc, argv, visual, cmap)
{
sysInit();
}
/*!
Special constructor for X11, ref. the documentation of
QApplication's corresponding constructor. The application identifier
will be \a appId. \a dpy, \a argc, \a
argv, \a visual, and \a cmap are passed on to the QApplication
constructor.
*/
QtSingleApplication::QtSingleApplication(Display* dpy, const QString &appId, int argc, char **argv, Qt::HANDLE visual, Qt::HANDLE cmap)
: QApplication(dpy, argc, argv, visual, cmap)
{
sysInit(appId);
}
# endif // Q_WS_X11
#endif // QT_VERSION < 0x050000
/*!
Returns true if another instance of this application is running;
otherwise false.
This function does not find instances of this application that are
being run by a different user (on Windows: that are running in
another session).
\sa sendMessage()
*/
bool QtSingleApplication::isRunning()
{
return peer->isClient();
}
/*!
Tries to send the text \a message to the currently running
instance. The QtSingleApplication object in the running instance
will emit the messageReceived() signal when it receives the
message.
This function returns true if the message has been sent to, and
processed by, the current instance. If there is no instance
currently running, or if the running instance fails to process the
message within \a timeout milliseconds, this function return false.
\sa isRunning(), messageReceived()
*/
bool QtSingleApplication::sendMessage(const QString &message, int timeout)
{
return peer->sendMessage(message, timeout);
}
/*!
Returns the application identifier. Two processes with the same
identifier will be regarded as instances of the same application.
*/
QString QtSingleApplication::id() const
{
return peer->applicationId();
}
/*!
Sets the activation window of this application to \a aw. The
activation window is the widget that will be activated by
activateWindow(). This is typically the application's main window.
If \a activateOnMessage is true (the default), the window will be
activated automatically every time a message is received, just prior
to the messageReceived() signal being emitted.
\sa activateWindow(), messageReceived()
*/
void QtSingleApplication::setActivationWindow(QWidget* aw, bool activateOnMessage)
{
actWin = aw;
if (activateOnMessage)
connect(peer, SIGNAL(messageReceived(const QString&)), this, SLOT(activateWindow()));
else
disconnect(peer, SIGNAL(messageReceived(const QString&)), this, SLOT(activateWindow()));
}
/*!
Returns the applications activation window if one has been set by
calling setActivationWindow(), otherwise returns 0.
\sa setActivationWindow()
*/
QWidget* QtSingleApplication::activationWindow() const
{
return actWin;
}
/*!
De-minimizes, raises, and activates this application's activation window.
This function does nothing if no activation window has been set.
This is a convenience function to show the user that this
application instance has been activated when he has tried to start
another instance.
This function should typically be called in response to the
messageReceived() signal. By default, that will happen
automatically, if an activation window has been set.
\sa setActivationWindow(), messageReceived(), initialize()
*/
void QtSingleApplication::activateWindow()
{
if (actWin) {
actWin->setWindowState(actWin->windowState() & ~Qt::WindowMinimized);
actWin->raise();
actWin->activateWindow();
}
}
/*!
\fn void QtSingleApplication::messageReceived(const QString& message)
This signal is emitted when the current instance receives a \a
message from another instance of this application.
\sa sendMessage(), setActivationWindow(), activateWindow()
*/
/*!
\fn void QtSingleApplication::initialize(bool dummy = true)
\obsolete
*/

View File

@ -0,0 +1,105 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QTSINGLEAPPLICATION_H
#define QTSINGLEAPPLICATION_H
#include <QApplication>
class QtLocalPeer;
#if defined(Q_OS_WIN)
# if !defined(QT_QTSINGLEAPPLICATION_EXPORT) && !defined(QT_QTSINGLEAPPLICATION_IMPORT)
# define QT_QTSINGLEAPPLICATION_EXPORT
# elif defined(QT_QTSINGLEAPPLICATION_IMPORT)
# if defined(QT_QTSINGLEAPPLICATION_EXPORT)
# undef QT_QTSINGLEAPPLICATION_EXPORT
# endif
# define QT_QTSINGLEAPPLICATION_EXPORT __declspec(dllimport)
# elif defined(QT_QTSINGLEAPPLICATION_EXPORT)
# undef QT_QTSINGLEAPPLICATION_EXPORT
# define QT_QTSINGLEAPPLICATION_EXPORT __declspec(dllexport)
# endif
#else
# define QT_QTSINGLEAPPLICATION_EXPORT
#endif
class QT_QTSINGLEAPPLICATION_EXPORT QtSingleApplication : public QApplication
{
Q_OBJECT
public:
QtSingleApplication(int &argc, char **argv, bool GUIenabled = true);
QtSingleApplication(const QString &id, int &argc, char **argv);
#if QT_VERSION < 0x050000
QtSingleApplication(int &argc, char **argv, Type type);
# if defined(Q_WS_X11)
QtSingleApplication(Display* dpy, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0);
QtSingleApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE cmap= 0);
QtSingleApplication(Display* dpy, const QString &appId, int argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0);
# endif // Q_WS_X11
#endif // QT_VERSION < 0x050000
bool isRunning();
QString id() const;
void setActivationWindow(QWidget* aw, bool activateOnMessage = true);
QWidget* activationWindow() const;
// Obsolete:
void initialize(bool dummy = true)
{ isRunning(); Q_UNUSED(dummy) }
public Q_SLOTS:
bool sendMessage(const QString &message, int timeout = 5000);
void activateWindow();
Q_SIGNALS:
void messageReceived(const QString &message);
private:
void sysInit(const QString &appId = QString());
QtLocalPeer *peer;
QWidget *actWin;
};
#endif // QTSINGLEAPPLICATION_H

View File

@ -0,0 +1,17 @@
#include(../common.pri)
INCLUDEPATH += $$PWD
DEPENDPATH += $$PWD
QT *= network
greaterThan(QT_MAJOR_VERSION, 4): QT *= widgets
qtsingleapplication-uselib:!qtsingleapplication-buildlib {
LIBS += -L$$QTSINGLEAPPLICATION_LIBDIR -l$$QTSINGLEAPPLICATION_LIBNAME
} else {
SOURCES += $$PWD/qtsingleapplication.cpp $$PWD/qtlocalpeer.cpp
HEADERS += $$PWD/qtsingleapplication.h $$PWD/qtlocalpeer.h
}
win32 {
contains(TEMPLATE, lib):contains(CONFIG, shared):DEFINES += QT_QTSINGLEAPPLICATION_EXPORT
else:qtsingleapplication-uselib:DEFINES += QT_QTSINGLEAPPLICATION_IMPORT
}

View File

@ -0,0 +1,149 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qtsinglecoreapplication.h"
#include "qtlocalpeer.h"
/*!
\class QtSingleCoreApplication qtsinglecoreapplication.h
\brief A variant of the QtSingleApplication class for non-GUI applications.
This class is a variant of QtSingleApplication suited for use in
console (non-GUI) applications. It is an extension of
QCoreApplication (instead of QApplication). It does not require
the QtGui library.
The API and usage is identical to QtSingleApplication, except that
functions relating to the "activation window" are not present, for
obvious reasons. Please refer to the QtSingleApplication
documentation for explanation of the usage.
A QtSingleCoreApplication instance can communicate to a
QtSingleApplication instance if they share the same application
id. Hence, this class can be used to create a light-weight
command-line tool that sends commands to a GUI application.
\sa QtSingleApplication
*/
/*!
Creates a QtSingleCoreApplication object. The application identifier
will be QCoreApplication::applicationFilePath(). \a argc and \a
argv are passed on to the QCoreAppliation constructor.
*/
QtSingleCoreApplication::QtSingleCoreApplication(int &argc, char **argv)
: QCoreApplication(argc, argv)
{
peer = new QtLocalPeer(this);
connect(peer, SIGNAL(messageReceived(const QString&)), SIGNAL(messageReceived(const QString&)));
}
/*!
Creates a QtSingleCoreApplication object with the application
identifier \a appId. \a argc and \a argv are passed on to the
QCoreAppliation constructor.
*/
QtSingleCoreApplication::QtSingleCoreApplication(const QString &appId, int &argc, char **argv)
: QCoreApplication(argc, argv)
{
peer = new QtLocalPeer(this, appId);
connect(peer, SIGNAL(messageReceived(const QString&)), SIGNAL(messageReceived(const QString&)));
}
/*!
Returns true if another instance of this application is running;
otherwise false.
This function does not find instances of this application that are
being run by a different user (on Windows: that are running in
another session).
\sa sendMessage()
*/
bool QtSingleCoreApplication::isRunning()
{
return peer->isClient();
}
/*!
Tries to send the text \a message to the currently running
instance. The QtSingleCoreApplication object in the running instance
will emit the messageReceived() signal when it receives the
message.
This function returns true if the message has been sent to, and
processed by, the current instance. If there is no instance
currently running, or if the running instance fails to process the
message within \a timeout milliseconds, this function return false.
\sa isRunning(), messageReceived()
*/
bool QtSingleCoreApplication::sendMessage(const QString &message, int timeout)
{
return peer->sendMessage(message, timeout);
}
/*!
Returns the application identifier. Two processes with the same
identifier will be regarded as instances of the same application.
*/
QString QtSingleCoreApplication::id() const
{
return peer->applicationId();
}
/*!
\fn void QtSingleCoreApplication::messageReceived(const QString& message)
This signal is emitted when the current instance receives a \a
message from another instance of this application.
\sa sendMessage()
*/

View File

@ -0,0 +1,71 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QTSINGLECOREAPPLICATION_H
#define QTSINGLECOREAPPLICATION_H
#include <QCoreApplication>
class QtLocalPeer;
class QtSingleCoreApplication : public QCoreApplication
{
Q_OBJECT
public:
QtSingleCoreApplication(int &argc, char **argv);
QtSingleCoreApplication(const QString &id, int &argc, char **argv);
bool isRunning();
QString id() const;
public Q_SLOTS:
bool sendMessage(const QString &message, int timeout = 5000);
Q_SIGNALS:
void messageReceived(const QString &message);
private:
QtLocalPeer* peer;
};
#endif // QTSINGLECOREAPPLICATION_H

View File

@ -0,0 +1,10 @@
INCLUDEPATH += $$PWD
DEPENDPATH += $$PWD
HEADERS += $$PWD/qtsinglecoreapplication.h $$PWD/qtlocalpeer.h
SOURCES += $$PWD/qtsinglecoreapplication.cpp $$PWD/qtlocalpeer.cpp
QT *= network
win32:contains(TEMPLATE, lib):contains(CONFIG, shared) {
DEFINES += QT_QTSINGLECOREAPPLICATION_EXPORT=__declspec(dllexport)
}

367
GlobalActionHelper.cpp Normal file
View File

@ -0,0 +1,367 @@
#include "GlobalActionHelper.h"
#include <QDebug>
#include <QApplication>
QHash<QPair<quint32, quint32>, QAction *> GlobalActionHelper::actions_;
void GlobalActionHelper::init () {
qApp->installNativeEventFilter (new GlobalActionHelper);
}
bool GlobalActionHelper::makeGlobal (QAction *action) {
QKeySequence hotKey = action->shortcut ();
if (hotKey.isEmpty ()) {
return true;
}
Qt::KeyboardModifiers allMods = Qt::ShiftModifier | Qt::ControlModifier |
Qt::AltModifier | Qt::MetaModifier;
Qt::Key key = hotKey.isEmpty () ?
Qt::Key (0) :
Qt::Key ((hotKey[0] ^ allMods) & hotKey[0]);
Qt::KeyboardModifiers mods = hotKey.isEmpty () ?
Qt::KeyboardModifiers (0) :
Qt::KeyboardModifiers (hotKey[0] & allMods);
const quint32 nativeKey = nativeKeycode (key);
const quint32 nativeMods = nativeModifiers (mods);
const bool res = registerHotKey (nativeKey, nativeMods);
if (res) {
actions_.insert (qMakePair (nativeKey, nativeMods), action);
}
else {
qWarning () << "Failed to register global hotkey:" << hotKey.toString ();
}
return res;
}
bool GlobalActionHelper::removeGlobal (QAction *action) {
QKeySequence hotKey = action->shortcut ();
if (hotKey.isEmpty ()) {
return true;
}
Qt::KeyboardModifiers allMods = Qt::ShiftModifier | Qt::ControlModifier |
Qt::AltModifier | Qt::MetaModifier;
Qt::Key key = hotKey.isEmpty () ?
Qt::Key (0) :
Qt::Key ((hotKey[0] ^ allMods) & hotKey[0]);
Qt::KeyboardModifiers mods = hotKey.isEmpty () ?
Qt::KeyboardModifiers (0) :
Qt::KeyboardModifiers (hotKey[0] & allMods);
const quint32 nativeKey = nativeKeycode (key);
const quint32 nativeMods = nativeModifiers (mods);
if (!actions_.contains (qMakePair (nativeKey, nativeMods))) {
return true;
}
const bool res = unregisterHotKey (nativeKey, nativeMods);
if (res) {
actions_.remove (qMakePair (nativeKey, nativeMods));
}
else {
qWarning () << "Failed to unregister global hotkey:" << hotKey.toString ();
}
return res;
}
void GlobalActionHelper::triggerHotKey (quint32 nativeKey, quint32 nativeMods) {
QAction *action = actions_.value (qMakePair (nativeKey, nativeMods));
if (action && action->isEnabled ()) {
action->activate (QAction::Trigger);
}
}
#if defined(Q_OS_LINUX)
# include <QX11Info>
# include <X11/Xlib.h>
# include <xcb/xcb_event.h>
static bool error = false;
static int customHandler (Display *display, XErrorEvent *event) {
Q_UNUSED (display);
switch (event->error_code) {
case BadAccess:
case BadValue:
case BadWindow:
if (event->request_code == 33 /* X_GrabKey */ ||
event->request_code == 34 /* X_UngrabKey */) {
error = true;
}
default:
return 0;
}
}
bool GlobalActionHelper::registerHotKey (quint32 nativeKey, quint32 nativeMods) {
Display *display = QX11Info::display ();
Window window = QX11Info::appRootWindow ();
Bool owner = True;
int pointer = GrabModeAsync;
int keyboard = GrabModeAsync;
error = false;
int (*handler)(Display *display, XErrorEvent *event) = XSetErrorHandler (customHandler);
XGrabKey (display, nativeKey, nativeMods, window, owner, pointer, keyboard);
// allow numlock
XGrabKey (display, nativeKey, nativeMods | Mod2Mask, window, owner, pointer, keyboard);
XSync (display, False);
XSetErrorHandler (handler);
return !error;
}
bool GlobalActionHelper::unregisterHotKey (quint32 nativeKey, quint32 nativeMods) {
Display *display = QX11Info::display ();
Window window = QX11Info::appRootWindow ();
error = false;
int (*handler)(Display *display, XErrorEvent *event) = XSetErrorHandler (customHandler);
XUngrabKey (display, nativeKey, nativeMods, window);
// allow numlock
XUngrabKey (display, nativeKey, nativeMods | Mod2Mask, window);
XSync (display, False);
XSetErrorHandler (handler);
return !error;
}
bool GlobalActionHelper::nativeEventFilter (const QByteArray &eventType,
void *message, long *result) {
Q_UNUSED (eventType);
Q_UNUSED (result);
xcb_generic_event_t *event = static_cast<xcb_generic_event_t *>(message);
if (event->response_type == XCB_KEY_PRESS) {
xcb_key_press_event_t *keyEvent = static_cast<xcb_key_press_event_t *>(message);
const quint32 keycode = keyEvent->detail;
const quint32 modifiers = keyEvent->state & ~XCB_MOD_MASK_2;
triggerHotKey (keycode, modifiers);
}
return false;
}
quint32 GlobalActionHelper::nativeKeycode (Qt::Key key) {
Display *display = QX11Info::display ();
KeySym keySym = XStringToKeysym (qPrintable (QKeySequence (key).toString ()));
return XKeysymToKeycode (display, keySym);
}
quint32 GlobalActionHelper::nativeModifiers (Qt::KeyboardModifiers modifiers) {
quint32 native = 0;
if (modifiers & Qt::ShiftModifier) {
native |= ShiftMask;
}
if (modifiers & Qt::ControlModifier) {
native |= ControlMask;
}
if (modifiers & Qt::AltModifier) {
native |= Mod1Mask;
}
if (modifiers & Qt::MetaModifier) {
native |= Mod4Mask;
}
return native;
}
#elif defined(Q_OS_WIN)
# include <qt_windows.h>
bool GlobalActionHelper::registerHotKey (quint32 nativeKey, quint32 nativeMods) {
return RegisterHotKey (0, nativeMods ^ nativeKey, nativeMods, nativeKey);
}
bool GlobalActionHelper::unregisterHotKey (quint32 nativeKey, quint32 nativeMods) {
return UnregisterHotKey (0, nativeMods ^ nativeKey);
}
bool GlobalActionHelper::nativeEventFilter (const QByteArray &eventType,
void *message, long *result) {
Q_UNUSED (eventType);
Q_UNUSED (result);
MSG *msg = static_cast<MSG *>(message);
if (msg->message == WM_HOTKEY) {
const quint32 keycode = HIWORD (msg->lParam);
const quint32 modifiers = LOWORD (msg->lParam);
triggerHotKey (keycode, modifiers);
}
return false;
}
quint32 GlobalActionHelper::nativeKeycode (Qt::Key key) {
switch (key) {
case Qt::Key_Escape:
return VK_ESCAPE;
case Qt::Key_Tab:
case Qt::Key_Backtab:
return VK_TAB;
case Qt::Key_Backspace:
return VK_BACK;
case Qt::Key_Return:
case Qt::Key_Enter:
return VK_RETURN;
case Qt::Key_Insert:
return VK_INSERT;
case Qt::Key_Delete:
return VK_DELETE;
case Qt::Key_Pause:
return VK_PAUSE;
case Qt::Key_Print:
return VK_PRINT;
case Qt::Key_Clear:
return VK_CLEAR;
case Qt::Key_Home:
return VK_HOME;
case Qt::Key_End:
return VK_END;
case Qt::Key_Left:
return VK_LEFT;
case Qt::Key_Up:
return VK_UP;
case Qt::Key_Right:
return VK_RIGHT;
case Qt::Key_Down:
return VK_DOWN;
case Qt::Key_PageUp:
return VK_PRIOR;
case Qt::Key_PageDown:
return VK_NEXT;
case Qt::Key_F1:
return VK_F1;
case Qt::Key_F2:
return VK_F2;
case Qt::Key_F3:
return VK_F3;
case Qt::Key_F4:
return VK_F4;
case Qt::Key_F5:
return VK_F5;
case Qt::Key_F6:
return VK_F6;
case Qt::Key_F7:
return VK_F7;
case Qt::Key_F8:
return VK_F8;
case Qt::Key_F9:
return VK_F9;
case Qt::Key_F10:
return VK_F10;
case Qt::Key_F11:
return VK_F11;
case Qt::Key_F12:
return VK_F12;
case Qt::Key_F13:
return VK_F13;
case Qt::Key_F14:
return VK_F14;
case Qt::Key_F15:
return VK_F15;
case Qt::Key_F16:
return VK_F16;
case Qt::Key_F17:
return VK_F17;
case Qt::Key_F18:
return VK_F18;
case Qt::Key_F19:
return VK_F19;
case Qt::Key_F20:
return VK_F20;
case Qt::Key_F21:
return VK_F21;
case Qt::Key_F22:
return VK_F22;
case Qt::Key_F23:
return VK_F23;
case Qt::Key_F24:
return VK_F24;
case Qt::Key_Space:
return VK_SPACE;
case Qt::Key_Asterisk:
return VK_MULTIPLY;
case Qt::Key_Plus:
return VK_ADD;
case Qt::Key_Comma:
return VK_SEPARATOR;
case Qt::Key_Minus:
return VK_SUBTRACT;
case Qt::Key_Slash:
return VK_DIVIDE;
case Qt::Key_MediaNext:
return VK_MEDIA_NEXT_TRACK;
case Qt::Key_MediaPrevious:
return VK_MEDIA_PREV_TRACK;
case Qt::Key_MediaPlay:
return VK_MEDIA_PLAY_PAUSE;
case Qt::Key_MediaStop:
return VK_MEDIA_STOP;
case Qt::Key_VolumeDown:
return VK_VOLUME_DOWN;
case Qt::Key_VolumeUp:
return VK_VOLUME_UP;
case Qt::Key_VolumeMute:
return VK_VOLUME_MUTE;
// numbers
case Qt::Key_0:
case Qt::Key_1:
case Qt::Key_2:
case Qt::Key_3:
case Qt::Key_4:
case Qt::Key_5:
case Qt::Key_6:
case Qt::Key_7:
case Qt::Key_8:
case Qt::Key_9:
return key;
// letters
case Qt::Key_A:
case Qt::Key_B:
case Qt::Key_C:
case Qt::Key_D:
case Qt::Key_E:
case Qt::Key_F:
case Qt::Key_G:
case Qt::Key_H:
case Qt::Key_I:
case Qt::Key_J:
case Qt::Key_K:
case Qt::Key_L:
case Qt::Key_M:
case Qt::Key_N:
case Qt::Key_O:
case Qt::Key_P:
case Qt::Key_Q:
case Qt::Key_R:
case Qt::Key_S:
case Qt::Key_T:
case Qt::Key_U:
case Qt::Key_V:
case Qt::Key_W:
case Qt::Key_X:
case Qt::Key_Y:
case Qt::Key_Z:
return key;
default:
return 0;
}
}
quint32 GlobalActionHelper::nativeModifiers (Qt::KeyboardModifiers modifiers) {
// MOD_ALT, MOD_CONTROL, (MOD_KEYUP), MOD_SHIFT, MOD_WIN
quint32 native = 0;
if (modifiers & Qt::ShiftModifier) {
native |= MOD_SHIFT;
}
if (modifiers & Qt::ControlModifier) {
native |= MOD_CONTROL;
}
if (modifiers & Qt::AltModifier) {
native |= MOD_ALT;
}
if (modifiers & Qt::MetaModifier) {
native |= MOD_WIN;
}
//if (modifiers & Qt::KeypadModifier)
//if (modifiers & Qt::GroupSwitchModifier)
return native;
}
#endif

29
GlobalActionHelper.h Normal file
View File

@ -0,0 +1,29 @@
#ifndef GLOBALACTIONHELPER_H
#define GLOBALACTIONHELPER_H
// Some functions copied from QXT lib
#include <QAbstractNativeEventFilter>
#include <QAction>
class GlobalActionHelper : public QAbstractNativeEventFilter {
public:
bool nativeEventFilter (const QByteArray &eventType, void *message,
long *result);
static void init ();
static bool makeGlobal (QAction *action);
static bool removeGlobal (QAction *action);
private:
static QHash<QPair<quint32, quint32>, QAction *> actions_;
static quint32 nativeKeycode (Qt::Key key);
static quint32 nativeModifiers (Qt::KeyboardModifiers modifiers);
static bool registerHotKey (quint32 nativeKey, quint32 nativeMods);
static bool unregisterHotKey (quint32 nativeKey, quint32 nativeMods);
static void triggerHotKey (quint32 nativeKey, quint32 nativeMods);
};
#endif // GLOBALACTIONHELPER_H

156
ImageProcessing.cpp Normal file
View File

@ -0,0 +1,156 @@
#include <QDebug>
#include <leptonica/allheaders.h>
#include <tesseract/host.h>
#include "ImageProcessing.h"
#include "StAssert.h"
#if defined(Q_OS_LINUX)
# include <fstream>
# include <limits>
qint64 getFreeMemory () {
std::string token;
std::ifstream file ("/proc/meminfo");
qint64 freeMem = 0;
while (file >> token) {
if (token == "MemFree:" || token == "Buffers:" || token == "Cached:") {
unsigned long mem = 0;
freeMem += (file >> mem) ? mem : 0;
}
}
return freeMem * 1024;
}
#elif defined(Q_OS_WIN)
# include <windows.h>
qint64 getFreeMemory () {
MEMORYSTATUSEX statex;
statex.dwLength = sizeof (statex);
if (GlobalMemoryStatusEx (&statex)) {
return statex.ullAvailPhys;
}
return -1;
}
#endif
Pix * convertImage (const QImage &image) {
PIX *pix;
int width = image.width ();
int height = image.height ();
int depth = image.depth ();
int bytesPerLine = image.bytesPerLine ();
int wpl = bytesPerLine / 4;
pix = pixCreate (width, height, depth);
pixSetWpl (pix, wpl);
pixSetColormap (pix, NULL);
memmove (pix->data, image.bits (), bytesPerLine * height);
const qreal toDPM = 1.0 / 0.0254;
int resolutionX = image.dotsPerMeterX () / toDPM;
int resolutionY = image.dotsPerMeterY () / toDPM;
if (resolutionX < 300) {
resolutionX = 300;
}
if (resolutionY < 300) {
resolutionY = 300;
}
pixSetResolution (pix, resolutionX, resolutionY);
return pix;
}
QImage convertImage (Pix &image) {
int width = pixGetWidth (&image);
int height = pixGetHeight (&image);
int depth = pixGetDepth (&image);
int bytesPerLine = pixGetWpl (&image) * 4;
l_uint32 *datas = pixGetData (&image);
QImage::Format format;
if (depth == 1) {
format = QImage::Format_Mono;
}
else if (depth == 8) {
format = QImage::Format_Indexed8;
}
else {
format = QImage::Format_RGB32;
}
QImage result ((uchar *)datas, width, height, bytesPerLine, format);
// Set resolution
l_int32 xres, yres;
pixGetResolution (&image, &xres, &yres);
const qreal toDPM = 1.0 / 0.0254;
result.setDotsPerMeterX (xres * toDPM);
result.setDotsPerMeterY (yres * toDPM);
// Handle pallete
QVector<QRgb> _bwCT;
_bwCT.append (qRgb (255,255,255));
_bwCT.append (qRgb (0,0,0));
QVector<QRgb> _grayscaleCT (256);
for (int i = 0; i < 256; i++) {
_grayscaleCT.append (qRgb (i, i, i));
}
switch (depth) {
case 1:
result.setColorTable (_bwCT);
break;
case 8:
result.setColorTable (_grayscaleCT);
break;
default:
result.setColorTable (_grayscaleCT);
}
if (result.isNull ()) {
static QImage none (0,0,QImage::Format_Invalid);
qDebug ("Invalid format!!!\n");
return none;
}
return result;
}
Pix * prepareImage (const QImage &image, int preferredScale) {
Pix *pix = convertImage (image);
ST_ASSERT (pix != NULL);
Pix *gray = pixConvertRGBToGray (pix, 0.0, 0.0, 0.0);
ST_ASSERT (gray != NULL);
pixDestroy (&pix);
Pix *scaled = gray;
if (preferredScale > 0) {
float maxScaleX = MAX_INT16 / double (gray->w);
float scaleX = std::min (float (preferredScale), maxScaleX);
float maxScaleY = MAX_INT16 / double (gray->h);
float scaleY = std::min (float (preferredScale), maxScaleY);
float scale = std::min (scaleX, scaleY);
qint64 availableMemory = getFreeMemory () * 0.95;
if (availableMemory > 0) {
qint32 actualSize = gray->w * gray->h * gray->d / 8;
float maxScaleMemory = float (availableMemory) / actualSize;
scale = std::min (scale, maxScaleMemory);
}
scaled = pixScale (gray, scale, scale);
if (scaled == NULL) {
scaled = gray;
}
}
if (scaled != gray) {
pixDestroy (&gray);
}
return scaled;
}
void cleanupImage (Pix **image) {
pixDestroy (image);
}

18
ImageProcessing.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef IMAGEPROCESSING_H
#define IMAGEPROCESSING_H
#include <QImage>
class Pix;
//! Convert QImage to Leptonica's PIX.
Pix * convertImage (const QImage &image);
//! Convert Leptonica's PIX to QImage.
QImage convertImage (Pix &image);
//! Propare image for OCR.
Pix * prepareImage (const QImage &image, int preferredScale);
//! Free allocated resources for image.
void cleanupImage (Pix **image);
#endif // IMAGEPROCESSING_H

301
LanguageHelper.cpp Normal file
View File

@ -0,0 +1,301 @@
#include <QDir>
#include <QSettings>
#include "LanguageHelper.h"
#include "Settings.h"
#include "StAssert.h"
LanguageHelper::LanguageHelper () {
init ();
}
QStringList LanguageHelper::availableOcrLanguagesUi () const {
QStringList uiItems;
foreach (const QString &item, availableOcrLanguages_) {
uiItems << ocrCodeToUi (item);
}
uiItems.sort ();
return uiItems;
}
const QStringList &LanguageHelper::availableOcrLanguages () const {
return availableOcrLanguages_;
}
QStringList LanguageHelper::availableOcrLanguages (const QString &path) const {
QDir dir (path + "/tessdata/");
if (!dir.exists ()) {
return QStringList ();
}
QStringList items;
QStringList files = dir.entryList (QStringList () << "*.traineddata", QDir::Files);
foreach (const QString &file, files) {
QString lang = file.left (file.indexOf ("."));
items << lang;
}
return items;
}
QStringList LanguageHelper::availableOcrLanguagesUi (const QString &path) const {
QStringList uiItems, items;
items = availableOcrLanguages (path);
foreach (const QString &item, items) {
uiItems << ocrCodeToUi (item);
}
uiItems.sort ();
return uiItems;
}
QStringList LanguageHelper::translateLanguagesUi () const {
QStringList uiItems = translateLanguages_.keys ();
uiItems.sort ();
return uiItems;
}
QStringList LanguageHelper::translateLanguages () const {
return translateLanguages_.values ();
}
QString LanguageHelper::translateCodeToUi (const QString &text) const {
return translateLanguages_.key (text, text);
}
QString LanguageHelper::translateUiToCode (const QString &text) const {
return translateLanguages_.value (text, text);
}
QString LanguageHelper::ocrCodeToUi (const QString &text) const {
return ocrLanguages_.key (text, text);
}
QString LanguageHelper::ocrUiToCode (const QString &text) const {
return ocrLanguages_.value (text, text);
}
QString LanguageHelper::ocrToTranslateCodes (const QString &text) const {
QString ocrUi = ocrCodeToUi (text);
QString translateCode = translateUiToCode (ocrUi);
if (translateCode == ocrUi) {
translateCode = "auto";
}
return translateCode;
}
QString LanguageHelper::translateToOcrCodes (const QString &text) const {
QString translateUi = translateCodeToUi (text);
QString ocrCode = ocrUiToCode (translateUi);
if (translateUi == ocrCode) {
return QString ();
}
return ocrCode;
}
void LanguageHelper::init () {
initOcrLanguages ();
initTranslateLanguages ();
updateAvailableOcrLanguages ();
}
void LanguageHelper::updateAvailableOcrLanguages () {
availableOcrLanguages_.clear ();
QSettings settings;
settings.beginGroup (settings_names::recogntionGroup);
QString tessDataPlace = settings.value (settings_names::tessDataPlace,
settings_values::tessDataPlace).toString ();
availableOcrLanguages_ = availableOcrLanguages (tessDataPlace);
}
void LanguageHelper::updateMenu (QMenu *menu, const QStringList &languages, int groupSize) const {
ST_ASSERT (menu != NULL);
menu->clear ();
if (languages.isEmpty ()) {
return;
}
if (languages.size () <= groupSize) {
foreach (const QString &language, languages) {
menu->addAction (language);
}
}
else {
int subIndex = groupSize;
QMenu *subMenu = NULL;
QString prevLetter;
foreach (const QString &language, languages) {
QString curLetter = language.left (1);
if (++subIndex >= groupSize && prevLetter != curLetter) {
if (subMenu != NULL) {
subMenu->setTitle (subMenu->title () + " - " + prevLetter);
}
subMenu = menu->addMenu (curLetter);
subIndex = 0;
}
prevLetter = curLetter;
subMenu->addAction (language);
}
subMenu->setTitle (subMenu->title () + " - " + prevLetter);
}
}
void LanguageHelper::initTranslateLanguages () {
translateLanguages_.insert (QObject::tr ("Afrikaans"),"af");
translateLanguages_.insert (QObject::tr ("Albanian"),"sq");
translateLanguages_.insert (QObject::tr ("Arabic"),"ar");
translateLanguages_.insert (QObject::tr ("Armenian"),"hy");
translateLanguages_.insert (QObject::tr ("Azerbaijani"),"az");
translateLanguages_.insert (QObject::tr ("Basque"),"eu");
translateLanguages_.insert (QObject::tr ("Belarusian"),"be");
translateLanguages_.insert (QObject::tr ("Bulgarian"),"bg");
translateLanguages_.insert (QObject::tr ("Catalan"),"ca");
translateLanguages_.insert (QObject::tr ("Chinese (Simplified)"),"zh-CN");
translateLanguages_.insert (QObject::tr ("Chinese (Traditional)"),"zh-TW");
translateLanguages_.insert (QObject::tr ("Croatian"),"hr");
translateLanguages_.insert (QObject::tr ("Czech"),"cs");
translateLanguages_.insert (QObject::tr ("Danish"),"da");
translateLanguages_.insert (QObject::tr ("Dutch"),"nl");
translateLanguages_.insert (QObject::tr ("English"),"en");
translateLanguages_.insert (QObject::tr ("Estonian"),"et");
translateLanguages_.insert (QObject::tr ("Filipino"),"tl");
translateLanguages_.insert (QObject::tr ("Finnish"),"fi");
translateLanguages_.insert (QObject::tr ("French"),"fr");
translateLanguages_.insert (QObject::tr ("Galician"),"gl");
translateLanguages_.insert (QObject::tr ("Georgian"),"ka");
translateLanguages_.insert (QObject::tr ("German"),"de");
translateLanguages_.insert (QObject::tr ("Greek"),"el");
translateLanguages_.insert (QObject::tr ("Haitian Creole"),"ht");
translateLanguages_.insert (QObject::tr ("Hebrew"),"iw");
translateLanguages_.insert (QObject::tr ("Hindi"),"hi");
translateLanguages_.insert (QObject::tr ("Hungarian"),"hu");
translateLanguages_.insert (QObject::tr ("Icelandic"),"is");
translateLanguages_.insert (QObject::tr ("Indonesian"),"id");
translateLanguages_.insert (QObject::tr ("Irish"),"ga");
translateLanguages_.insert (QObject::tr ("Italian"),"it");
translateLanguages_.insert (QObject::tr ("Japanese"),"ja");
translateLanguages_.insert (QObject::tr ("Korean"),"ko");
translateLanguages_.insert (QObject::tr ("Latvian"),"lv");
translateLanguages_.insert (QObject::tr ("Lithuanian"),"lt");
translateLanguages_.insert (QObject::tr ("Macedonian"),"mk");
translateLanguages_.insert (QObject::tr ("Malay"),"ms");
translateLanguages_.insert (QObject::tr ("Maltese"),"mt");
translateLanguages_.insert (QObject::tr ("Norwegian"),"no");
translateLanguages_.insert (QObject::tr ("Persian"),"fa");
translateLanguages_.insert (QObject::tr ("Polish"),"pl");
translateLanguages_.insert (QObject::tr ("Portuguese"),"pt");
translateLanguages_.insert (QObject::tr ("Romanian"),"ro");
translateLanguages_.insert (QObject::tr ("Russian"),"ru");
translateLanguages_.insert (QObject::tr ("Serbian"),"sr");
translateLanguages_.insert (QObject::tr ("Slovak"),"sk");
translateLanguages_.insert (QObject::tr ("Slovenian"),"sl");
translateLanguages_.insert (QObject::tr ("Spanish"),"es");
translateLanguages_.insert (QObject::tr ("Swahili"),"sw");
translateLanguages_.insert (QObject::tr ("Swedish"),"sv");
translateLanguages_.insert (QObject::tr ("Thai"),"th");
translateLanguages_.insert (QObject::tr ("Turkish"),"tr");
translateLanguages_.insert (QObject::tr ("Ukrainian"),"uk");
translateLanguages_.insert (QObject::tr ("Urdu"),"ur");
translateLanguages_.insert (QObject::tr ("Vietnamese"),"vi");
translateLanguages_.insert (QObject::tr ("Welsh"),"cy");
translateLanguages_.insert (QObject::tr ("Yiddish"),"yi");
}
void LanguageHelper::initOcrLanguages () {
ocrLanguages_.insert (QObject::tr ("Ancient Greek"),"grc");
ocrLanguages_.insert (QObject::tr ("Esperanto alternative"),"epo_alt");
ocrLanguages_.insert (QObject::tr ("English"),"eng");
ocrLanguages_.insert (QObject::tr ("Ukrainian"),"ukr");
ocrLanguages_.insert (QObject::tr ("Turkish"),"tur");
ocrLanguages_.insert (QObject::tr ("Thai"),"tha");
ocrLanguages_.insert (QObject::tr ("Tagalog"),"tgl");
ocrLanguages_.insert (QObject::tr ("Telugu"),"tel");
ocrLanguages_.insert (QObject::tr ("Tamil"),"tam");
ocrLanguages_.insert (QObject::tr ("Swedish"),"swe");
ocrLanguages_.insert (QObject::tr ("Swahili"),"swa");
ocrLanguages_.insert (QObject::tr ("Serbian"),"srp");
ocrLanguages_.insert (QObject::tr ("Albanian"),"sqi");
ocrLanguages_.insert (QObject::tr ("Spanish"),"spa");
ocrLanguages_.insert (QObject::tr ("Slovenian"),"slv");
ocrLanguages_.insert (QObject::tr ("Slovakian"),"slk");
ocrLanguages_.insert (QObject::tr ("Romanian"),"ron");
ocrLanguages_.insert (QObject::tr ("Portuguese"),"por");
ocrLanguages_.insert (QObject::tr ("Polish"),"pol");
ocrLanguages_.insert (QObject::tr ("Norwegian"),"nor");
ocrLanguages_.insert (QObject::tr ("Dutch"),"nld");
ocrLanguages_.insert (QObject::tr ("Malay"),"msa");
ocrLanguages_.insert (QObject::tr ("Maltese"),"mlt");
ocrLanguages_.insert (QObject::tr ("Macedonian"),"mkd");
ocrLanguages_.insert (QObject::tr ("Malayalam"),"mal");
ocrLanguages_.insert (QObject::tr ("Lithuanian"),"lit");
ocrLanguages_.insert (QObject::tr ("Latvian"),"lav");
ocrLanguages_.insert (QObject::tr ("Korean"),"kor");
ocrLanguages_.insert (QObject::tr ("Kannada"),"kan");
ocrLanguages_.insert (QObject::tr ("Italian"),"ita");
ocrLanguages_.insert (QObject::tr ("Icelandic"),"isl");
ocrLanguages_.insert (QObject::tr ("Indonesian"),"ind");
ocrLanguages_.insert (QObject::tr ("Cherokee"),"chr");
ocrLanguages_.insert (QObject::tr ("Hungarian"),"hun");
ocrLanguages_.insert (QObject::tr ("Croatian"),"hrv");
ocrLanguages_.insert (QObject::tr ("Hindi"),"hin");
ocrLanguages_.insert (QObject::tr ("Hebrew"),"heb");
ocrLanguages_.insert (QObject::tr ("Galician"),"glg");
ocrLanguages_.insert (QObject::tr ("Middle French (ca. 1400-1600)"),"frm");
ocrLanguages_.insert (QObject::tr ("Frankish"),"frk");
ocrLanguages_.insert (QObject::tr ("French"),"fra");
ocrLanguages_.insert (QObject::tr ("Finnish"),"fin");
ocrLanguages_.insert (QObject::tr ("Basque"),"eus");
ocrLanguages_.insert (QObject::tr ("Estonian"),"est");
ocrLanguages_.insert (QObject::tr ("Math / equation"),"equ");
ocrLanguages_.insert (QObject::tr ("Esperanto"),"epo");
ocrLanguages_.insert (QObject::tr ("Middle English (1100-1500)"),"enm");
ocrLanguages_.insert (QObject::tr ("Greek"),"ell");
ocrLanguages_.insert (QObject::tr ("German"),"deu");
ocrLanguages_.insert (QObject::tr ("Danish"),"dan");
ocrLanguages_.insert (QObject::tr ("Czech"),"ces");
ocrLanguages_.insert (QObject::tr ("Catalan"),"cat");
ocrLanguages_.insert (QObject::tr ("Bulgarian"),"bul");
ocrLanguages_.insert (QObject::tr ("Bengali"),"ben");
ocrLanguages_.insert (QObject::tr ("Belarusian"),"bel");
ocrLanguages_.insert (QObject::tr ("Azerbaijani"),"aze");
ocrLanguages_.insert (QObject::tr ("Arabic"),"ara");
ocrLanguages_.insert (QObject::tr ("Afrikaans"),"afr");
ocrLanguages_.insert (QObject::tr ("Japanese"),"jpn");
ocrLanguages_.insert (QObject::tr ("Chinese (Simplified)"),"chi_sim");
ocrLanguages_.insert (QObject::tr ("Chinese (Traditional)"),"chi_tra");
ocrLanguages_.insert (QObject::tr ("Russian"),"rus");
ocrLanguages_.insert (QObject::tr ("Vietnamese"),"vie");
ocrLanguages_.insert (QObject::tr ("Amharic"),"amh");
ocrLanguages_.insert (QObject::tr ("Assamese"),"asm");
ocrLanguages_.insert (QObject::tr ("Tibetan"),"bod");
ocrLanguages_.insert (QObject::tr ("Bosnian"),"bos");
ocrLanguages_.insert (QObject::tr ("Cebuano"),"ceb");
ocrLanguages_.insert (QObject::tr ("Welsh"),"cym");
ocrLanguages_.insert (QObject::tr ("Dzongkha"),"dzo");
ocrLanguages_.insert (QObject::tr ("Persian"),"fas");
ocrLanguages_.insert (QObject::tr ("Irish"),"gle");
ocrLanguages_.insert (QObject::tr ("Gujarati"),"guj");
ocrLanguages_.insert (QObject::tr ("Haitian"),"hat");
ocrLanguages_.insert (QObject::tr ("Inuktitut"),"iku");
ocrLanguages_.insert (QObject::tr ("Javanese"),"jav");
ocrLanguages_.insert (QObject::tr ("Georgian"),"kat");
ocrLanguages_.insert (QObject::tr ("Kazakh"),"kaz");
ocrLanguages_.insert (QObject::tr ("Khmer"),"khm");
ocrLanguages_.insert (QObject::tr ("Kirghiz"),"kir");
ocrLanguages_.insert (QObject::tr ("Kurdish"),"kur");
ocrLanguages_.insert (QObject::tr ("Lao"),"lao");
ocrLanguages_.insert (QObject::tr ("Latin"),"lat");
ocrLanguages_.insert (QObject::tr ("Marathi"),"mar");
ocrLanguages_.insert (QObject::tr ("Burmese"),"mya");
ocrLanguages_.insert (QObject::tr ("Nepali"),"nep");
ocrLanguages_.insert (QObject::tr ("Oriya"),"ori");
ocrLanguages_.insert (QObject::tr ("Panjabi"),"pan");
ocrLanguages_.insert (QObject::tr ("Pushto"),"pus");
ocrLanguages_.insert (QObject::tr ("Sanskrit"),"san");
ocrLanguages_.insert (QObject::tr ("Sinhala"),"sin");
ocrLanguages_.insert (QObject::tr ("Syriac"),"syr");
ocrLanguages_.insert (QObject::tr ("Tajik"),"tgk");
ocrLanguages_.insert (QObject::tr ("Tigrinya"),"tir");
ocrLanguages_.insert (QObject::tr ("Uighur"),"uig");
ocrLanguages_.insert (QObject::tr ("Urdu"),"urd");
ocrLanguages_.insert (QObject::tr ("Uzbek"),"uzb");
ocrLanguages_.insert (QObject::tr ("Yiddish"),"yid");
}

43
LanguageHelper.h Normal file
View File

@ -0,0 +1,43 @@
#ifndef LANGUAGEHELPER_H
#define LANGUAGEHELPER_H
#include <QMap>
#include <QStringList>
#include <QMenu>
class LanguageHelper {
public:
LanguageHelper ();
QStringList availableOcrLanguagesUi () const;
const QStringList &availableOcrLanguages () const;
QStringList availableOcrLanguagesUi (const QString &path) const;
QStringList translateLanguagesUi () const;
QStringList translateLanguages () const;
QString translateCodeToUi (const QString &text) const;
QString translateUiToCode (const QString &text) const;
QString ocrCodeToUi (const QString &text) const;
QString ocrUiToCode (const QString &text) const;
QString ocrToTranslateCodes (const QString &text) const;
QString translateToOcrCodes (const QString &text) const;
void updateAvailableOcrLanguages ();
//! Update languages menu. Group items into submenus if needed.
void updateMenu (QMenu *menu, const QStringList &languages, int groupSize = 10) const;
private:
QStringList availableOcrLanguages (const QString &path) const;
void init ();
void initTranslateLanguages ();
void initOcrLanguages ();
private:
QStringList availableOcrLanguages_;
QMap<QString, QString> translateLanguages_;
QMap<QString, QString> ocrLanguages_;
};
#endif // LANGUAGEHELPER_H

457
Manager.cpp Normal file
View File

@ -0,0 +1,457 @@
#include "Manager.h"
#include <QDebug>
#include <QMenu>
#include <QApplication>
#include <QDesktopWidget>
#include <QScreen>
#include <QDesktopWidget>
#include <QThread>
#include <QSettings>
#include <QClipboard>
#include <QMessageBox>
#include <QInputDialog>
#include <QNetworkProxy>
#include "Settings.h"
#include "SettingsEditor.h"
#include "SelectionDialog.h"
#include "GlobalActionHelper.h"
#include "Recognizer.h"
#include "WebTranslator.h"
#include "ResultDialog.h"
#include "LanguageHelper.h"
#include "StAssert.h"
#include "Utils.h"
#include "Updater.h"
Manager::Manager (QObject *parent) :
QObject (parent),
trayIcon_ (new QSystemTrayIcon (this)),
dictionary_ (new LanguageHelper),
resultDialog_ (new ResultDialog (*dictionary_)),
updater_ (new Updater (this)), updateTimer_ (new QTimer (this)),
captureAction_ (NULL), repeatCaptureAction_ (NULL),
repeatAction_ (NULL), clipboardAction_ (NULL),
useResultDialog_ (true), doTranslation_ (true), itemProcessingCount_ (0) {
updateNormalIcon ();
GlobalActionHelper::init ();
qRegisterMetaType<ProcessingItem>();
// Recognizer
Recognizer *recognizer = new Recognizer;
connect (this, SIGNAL (requestRecognize (ProcessingItem)),
recognizer, SLOT (recognize (ProcessingItem)));
connect (recognizer, SIGNAL (recognized (ProcessingItem)),
this, SIGNAL (requestTranslate (ProcessingItem)));
connect (recognizer, SIGNAL (error (QString)),
SLOT (showError (QString)));
connect (this, SIGNAL (settingsEdited ()),
recognizer, SLOT (applySettings ()));
QThread *recognizerThread = new QThread (this);
threads_ << recognizerThread;
recognizer->moveToThread (recognizerThread);
recognizerThread->start ();
connect (qApp, SIGNAL (aboutToQuit ()), recognizerThread, SLOT (quit ()));
// Translator
WebTranslator *translator = new WebTranslator;
connect (this, SIGNAL (requestTranslate (ProcessingItem)),
translator, SLOT (translate (ProcessingItem)));
connect (translator, SIGNAL (translated (ProcessingItem)),
SLOT (showResult (ProcessingItem)));
connect (translator, SIGNAL (error (QString)),
SLOT (showError (QString)));
connect (this, SIGNAL (settingsEdited ()),
translator, SLOT (applySettings ()));
connect (this, SIGNAL (settingsEdited ()), this, SLOT (applySettings ()));
connect (updater_, SIGNAL (updated ()), SIGNAL (settingsEdited ()));
connect (updater_, SIGNAL (error (QString)), SLOT (showError (QString)));
updateTimer_->setSingleShot (true);
connect (updateTimer_, SIGNAL (timeout ()), SLOT (checkForUpdates ()));
resultDialog_->setWindowIcon (trayIcon_->icon ());
connect (this, SIGNAL (settingsEdited ()), resultDialog_, SLOT (applySettings ()));
connect (resultDialog_, SIGNAL (requestRecognize (ProcessingItem)),
this, SIGNAL (requestRecognize (ProcessingItem)));
connect (resultDialog_, SIGNAL (requestTranslate (ProcessingItem)),
this, SIGNAL (requestTranslate (ProcessingItem)));
connect (resultDialog_, SIGNAL (requestClipboard ()), SLOT (copyLastToClipboard ()));
connect (resultDialog_, SIGNAL (requestImageClipboard ()),
SLOT (copyLastImageToClipboard ()));
connect (resultDialog_, SIGNAL (requestEdition (ProcessingItem)),
this, SLOT (editRecognized (ProcessingItem)));
connect (trayIcon_, SIGNAL (activated (QSystemTrayIcon::ActivationReason)),
SLOT (processTrayAction (QSystemTrayIcon::ActivationReason)));
trayIcon_->setContextMenu (trayContextMenu ());
updateActionsState ();
trayIcon_->show ();
applySettings ();
}
QMenu * Manager::trayContextMenu () {
QMenu *menu = new QMenu ();
captureAction_ = menu->addAction (tr ("Захват"), this, SLOT (capture ()));
repeatCaptureAction_ = menu->addAction (tr ("Повторить захват"),
this, SLOT (repeatCapture ()));
QMenu *translateMenu = menu->addMenu (tr ("Результат"));
repeatAction_ = translateMenu->addAction (tr ("Показать"), this,
SLOT (showLast ()));
clipboardAction_ = translateMenu->addAction (tr ("В буфер"), this,
SLOT (copyLastToClipboard ()));
menu->addAction (tr ("Настройки"), this, SLOT (settings ()));
menu->addAction (tr ("О программе"), this, SLOT (about ()));
menu->addAction (tr ("Выход"), this, SLOT (close ()));
return menu;
}
void Manager::updateActionsState (bool isEnabled) {
#ifdef Q_OS_LINUX
// Avoid unneeded tray blinking (required to update context menu).
QList<QAction *> actions;
actions << captureAction_ << repeatCaptureAction_ << repeatAction_ << clipboardAction_;
QList<bool> states;
foreach (const QAction * action, actions) {
states << action->isEnabled ();
}
#endif
captureAction_->setEnabled (isEnabled);
repeatCaptureAction_->setEnabled (isEnabled && !selections_.isEmpty ());
const ProcessingItem &lastItem = resultDialog_->item ();
repeatAction_->setEnabled (isEnabled && lastItem.isValid ());
clipboardAction_->setEnabled (isEnabled && lastItem.isValid ());
#ifdef Q_OS_LINUX
for (int i = 0, end = actions.size (); i < end; ++i) {
if (states.at (i) != actions.at (i)->isEnabled ()) {
trayIcon_->hide ();
trayIcon_->show ();
break;
}
}
#endif
}
void Manager::applySettings () {
#define GET(NAME) settings.value (settings_names::NAME, settings_values::NAME)
QSettings settings;
settings.beginGroup (settings_names::guiGroup);
QStringList globalActionsFailed;
Q_CHECK_PTR (captureAction_);
GlobalActionHelper::removeGlobal (captureAction_);
captureAction_->setShortcut (GET (captureHotkey).toString ());
if (!GlobalActionHelper::makeGlobal (captureAction_)) {
globalActionsFailed << captureAction_->shortcut ().toString ();
}
Q_CHECK_PTR (repeatCaptureAction_);
GlobalActionHelper::removeGlobal (repeatCaptureAction_);
repeatCaptureAction_->setShortcut (GET (repeatCaptureHotkey).toString ());
if (!GlobalActionHelper::makeGlobal (repeatCaptureAction_)) {
globalActionsFailed << repeatCaptureAction_->shortcut ().toString ();
}
Q_CHECK_PTR (repeatAction_);
GlobalActionHelper::removeGlobal (repeatAction_);
repeatAction_->setShortcut (GET (repeatHotkey).toString ());
if (!GlobalActionHelper::makeGlobal (repeatAction_)) {
globalActionsFailed << repeatAction_->shortcut ().toString ();
}
Q_CHECK_PTR (clipboardAction_);
GlobalActionHelper::removeGlobal (clipboardAction_);
clipboardAction_->setShortcut (GET (clipboardHotkey).toString ());
if (!GlobalActionHelper::makeGlobal (clipboardAction_)) {
globalActionsFailed << clipboardAction_->shortcut ().toString ();
}
if (!globalActionsFailed.isEmpty ()) {
showError (tr ("Failed to register global shortcuts:\n%1")
.arg (globalActionsFailed.join ("\n")));
}
// Depends on SettingsEditor button indexes. 1==dialog
useResultDialog_ = GET (resultShowType).toBool ();
QNetworkProxy proxy = QNetworkProxy::applicationProxy ();
QList<int> proxyTypes = proxyTypeOrder ();
int proxyTypeIndex = std::min (GET (proxyType).toInt (), proxyTypes.size ());
proxy.setType (QNetworkProxy::ProxyType (proxyTypes.at (std::max (proxyTypeIndex, 0))));
proxy.setHostName (GET (proxyHostName).toString ());
proxy.setPort (GET (proxyPort).toInt ());
proxy.setUser (GET (proxyUser).toString ());
if (GET (proxySavePassword).toBool ()) {
proxy.setPassword (encode (GET (proxyPassword).toString ()));
}
QNetworkProxy::setApplicationProxy (proxy);
scheduleUpdate ();
settings.endGroup ();
settings.beginGroup (settings_names::recogntionGroup);
defaultOrcLanguage_ = GET (ocrLanguage).toString ();
settings.endGroup ();
settings.beginGroup (settings_names::translationGroup);
defaultTranslationLanguage_ = GET (translationLanguage).toString ();
doTranslation_ = GET (doTranslation).toBool ();
settings.endGroup ();
Q_CHECK_PTR (dictionary_);
dictionary_->updateAvailableOcrLanguages ();
#undef GET
}
void Manager::scheduleUpdate (bool justChecked) {
#define GET(NAME) settings.value (settings_names::NAME, settings_values::NAME)
QSettings settings;
settings.beginGroup (settings_names::guiGroup);
updateTimer_->stop ();
if (justChecked) {
settings.setValue (settings_names::lastUpdateCheck, QDateTime::currentDateTime ());
}
QDateTime nextUpdateCheck = updater_->nextCheckTime (GET (lastUpdateCheck).toDateTime (),
GET (autoUpdateType).toInt ());
if (nextUpdateCheck.isValid ()) {
updateTimer_->start (QDateTime::currentDateTime ().msecsTo (nextUpdateCheck));
}
#undef GET
}
void Manager::checkForUpdates () {
updater_->checkForUpdates ();
scheduleUpdate (true);
}
Manager::~Manager () {
foreach (SelectionDialog * selection, selections_.values ()) {
selection->hide ();
delete selection;
}
trayIcon_->hide ();
delete trayIcon_->contextMenu ();
foreach (QThread * thread, threads_) {
thread->quit ();
thread->wait (1000000);
}
}
void Manager::capture () {
QList<QScreen *> screens = QApplication::screens ();
foreach (QScreen * screen, screens) {
QRect geometry = screen->availableGeometry ();
QPixmap pixmap = screen->grabWindow (0, geometry.x (), geometry.y (),
geometry.width (), geometry.height ());
QString name = screen->name ();
if (!selections_.contains (name)) {
SelectionDialog *selection = new SelectionDialog (*dictionary_);
selection->setWindowIcon (trayIcon_->icon ());
connect (this, SIGNAL (closeSelections ()), selection, SLOT (close ()));
connect (this, SIGNAL (settingsEdited ()), selection, SLOT (applySettings ()));
connect (selection, SIGNAL (selected (ProcessingItem)),
SLOT (handleSelection (ProcessingItem)));
connect (selection, SIGNAL (rejected ()), SIGNAL (closeSelections ()));
selections_[name] = selection;
}
SelectionDialog *selection = selections_[name];
selection->setPixmap (pixmap, geometry);
}
updateActionsState ();
}
void Manager::handleSelection (ProcessingItem item) {
bool altMod = item.modifiers & Qt::AltModifier;
bool doTranslation = (doTranslation_ && !altMod) || (!doTranslation_ && altMod);
if (doTranslation) {
item.translateLanguage = defaultTranslationLanguage_;
}
if (item.ocrLanguage.isEmpty ()) {
item.ocrLanguage = defaultOrcLanguage_;
}
if (item.swapLanguages_) {
QString translate = (item.translateLanguage.isEmpty ())
? defaultTranslationLanguage_ : item.translateLanguage;
if (doTranslation) {
item.translateLanguage = dictionary_->ocrToTranslateCodes (item.ocrLanguage);
}
item.sourceLanguage.clear ();
item.ocrLanguage = dictionary_->translateToOcrCodes (translate);
if (item.ocrLanguage.isEmpty ()) {
showError (tr ("Не найден подходящий язык распознавания."));
return;
}
}
if (item.sourceLanguage.isEmpty ()) {
item.sourceLanguage = dictionary_->ocrToTranslateCodes (item.ocrLanguage);
}
emit requestRecognize (item);
++itemProcessingCount_;
updateNormalIcon ();
if (!(item.modifiers & Qt::ControlModifier)) {
emit closeSelections ();
}
}
void Manager::repeatCapture () {
if (selections_.isEmpty ()) {
return;
}
QList<QScreen *> screens = QApplication::screens ();
foreach (QScreen * screen, screens) {
QString name = screen->name ();
if (!selections_.contains (name)) {
continue;
}
SelectionDialog *selection = selections_[name];
selection->show ();
selection->activateWindow ();
}
}
void Manager::settings () {
SettingsEditor editor (*dictionary_);
editor.setWindowIcon (trayIcon_->icon ());
connect (&editor, SIGNAL (settingsEdited ()), SIGNAL (settingsEdited ()));
connect (&editor, SIGNAL (updateCheckRequested ()), SLOT (checkForUpdates ()));
updateActionsState (false);
editor.exec ();
updateActionsState (true);
}
void Manager::close () {
QApplication::quit ();
}
void Manager::about () {
QString text = tr ("Программа для распознавания текста на экране.\n" \
"Создана с использованием Qt, tesseract-ocr, Google Translate.\n"
"Автор: Gres (translator@gres.biz)\n"
"Версия: %1 от %2 %3").arg (updater_->currentAppVersion ())
.arg (__DATE__).arg (__TIME__);
QString tips = tr ("\n\nПодсказки.\n"
"Клик по иконке в трее:\n"
"* левой кнопкой - отобразить последний результат\n"
"* средней кнопкой - скопировать последний результат в буфер обмена\n"
#ifdef Q_OS_WIN
"* двойной клик - повторный захват последнего экрана\n"
#endif
"\n"
"Захвата изображения при зажатых кнопках:\n"
"* Ctrl - не выходить из режима захвата\n"
"* Alt - выполнить перевод, если в настройках он выключен "
"(и наоборот, не выполнять, если включен)\n"
"");
QMessageBox message (QMessageBox::Information, tr ("О программе"), text + tips,
QMessageBox::Ok);
message.setIconPixmap (trayIcon_->icon ().pixmap (QSize (64, 64)));
message.exec ();
}
void Manager::processTrayAction (QSystemTrayIcon::ActivationReason reason) {
if (reason == QSystemTrayIcon::Trigger && repeatAction_->isEnabled ()) {
showLast ();
}
else if (reason == QSystemTrayIcon::MiddleClick && clipboardAction_->isEnabled ()) {
copyLastToClipboard ();
trayIcon_->showMessage (tr ("Результат"),
tr ("Последний результат был скопирован в буфер обмена."),
QSystemTrayIcon::Information);
}
else if (reason == QSystemTrayIcon::DoubleClick && repeatCaptureAction_->isEnabled ()) {
repeatCapture ();
}
}
void Manager::editRecognized (ProcessingItem item) {
QString fixed = QInputDialog::getMultiLineText (
NULL, tr ("Правка"), tr ("Исправьте распознанный текст"), item.recognized);
if (!fixed.isEmpty ()) {
item.recognized = fixed;
++itemProcessingCount_;
updateNormalIcon ();
emit requestTranslate (item);
}
}
void Manager::showLast () {
const ProcessingItem &item = resultDialog_->item ();
if (item.isValid ()) {
++itemProcessingCount_;
showResult (item);
}
}
void Manager::copyLastToClipboard () {
const ProcessingItem &item = resultDialog_->item ();
if (item.isValid ()) {
QClipboard *clipboard = QApplication::clipboard ();
QString message = item.recognized;
if (!item.translated.isEmpty ()) {
message += " - " + item.translated;
}
clipboard->setText (message);
}
}
void Manager::copyLastImageToClipboard () {
const ProcessingItem &item = resultDialog_->item ();
if (item.isValid ()) {
QClipboard *clipboard = QApplication::clipboard ();
clipboard->setPixmap (item.source);
}
}
void Manager::showResult (ProcessingItem item) {
--itemProcessingCount_;
if (!item.isValid ()) {
// delay because it can show error
QTimer::singleShot (3000, this, SLOT (updateNormalIcon ()));
return;
}
changeIcon (IconTypeSuccess);
if (useResultDialog_) {
resultDialog_->showResult (item);
}
else {
QString message = item.recognized + " - " + item.translated;
trayIcon_->showMessage (tr ("Результат"), message, QSystemTrayIcon::Information);
}
updateActionsState ();
}
void Manager::showError (QString text) {
qCritical () << text;
changeIcon (IconTypeError);
trayIcon_->showMessage (tr ("Ошибка"), text, QSystemTrayIcon::Critical);
}
void Manager::changeIcon (int iconType, int timeoutMsec) {
QString fileName;
switch (iconType) {
case IconTypeSuccess:
fileName = ":/images/STIconGreen.png";
break;
case IconTypeError:
fileName = ":/images/STIconRed.png";
break;
default:
return;
}
trayIcon_->setIcon (QIcon (fileName));
if (timeoutMsec > 0) {
QTimer::singleShot (timeoutMsec, this, SLOT (updateNormalIcon ()));
}
}
void Manager::updateNormalIcon () {
QString fileName = itemProcessingCount_ > 0
? ":/images/STIconOrange.png" : ":/images/STIconBlue.png";
trayIcon_->setIcon (QIcon (fileName));
}

84
Manager.h Normal file
View File

@ -0,0 +1,84 @@
#ifndef MANAGER_H
#define MANAGER_H
#include <QPixmap>
#include <QSystemTrayIcon>
#include <QMap>
#include "ProcessingItem.h"
class QAction;
class QMenu;
class SelectionDialog;
class ResultDialog;
class LanguageHelper;
class Updater;
class Manager : public QObject {
Q_OBJECT
enum IconType {
IconTypeNormal, IconTypeWorking, IconTypeError, IconTypeSuccess
};
public:
explicit Manager (QObject *parent = 0);
~Manager ();
signals:
void requestRecognize (ProcessingItem item);
void requestTranslate (ProcessingItem item);
void closeSelections ();
void settingsEdited ();
private slots:
void capture ();
void repeatCapture ();
void settings ();
void close ();
void about ();
void showLast ();
void copyLastToClipboard ();
void copyLastImageToClipboard ();
void applySettings ();
void checkForUpdates ();
void processTrayAction (QSystemTrayIcon::ActivationReason reason);
void editRecognized (ProcessingItem item);
void handleSelection (ProcessingItem item);
void showResult (ProcessingItem item);
void showError (QString text);
void updateNormalIcon ();
private:
QMenu * trayContextMenu ();
void updateActionsState (bool isEnabled = true);
void changeIcon (int iconType, int timeoutMsec = 3000);
void scheduleUpdate (bool justChecked = false);
private:
QSystemTrayIcon *trayIcon_;
LanguageHelper *dictionary_;
//! Selection dialogs for each screen. Key - screen name.
QMap<QString, SelectionDialog *> selections_;
ResultDialog *resultDialog_;
Updater *updater_;
QTimer *updateTimer_;
QAction *captureAction_;
QAction *repeatCaptureAction_;
QAction *repeatAction_;
QAction *clipboardAction_;
bool useResultDialog_;
//! Used threads. For proper termination.
QList<QThread *> threads_;
QString defaultTranslationLanguage_;
QString defaultOrcLanguage_;
bool doTranslation_;
int itemProcessingCount_;
};
#endif // MANAGER_H

17
ProcessingItem.cpp Normal file
View File

@ -0,0 +1,17 @@
#include "ProcessingItem.h"
ProcessingItem::ProcessingItem ()
: swapLanguages_ (false) {
}
bool ProcessingItem::isValid (bool checkOnlyInput) const {
bool valid = true;
valid &= (!screenPos.isNull ());
valid &= (!source.isNull ());
valid &= (!ocrLanguage.isEmpty ());
if (!checkOnlyInput) {
valid &= (!recognized.isEmpty ());
}
return valid;
}

24
ProcessingItem.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef PROCESSINGITEM_H
#define PROCESSINGITEM_H
#include <QPixmap>
struct ProcessingItem {
ProcessingItem ();
QPoint screenPos;
QPixmap source;
QString recognized;
QString translated;
QString ocrLanguage;
QString sourceLanguage;
QString translateLanguage;
Qt::KeyboardModifiers modifiers;
bool swapLanguages_;
bool isValid (bool checkOnlyInput = false) const;
};
Q_DECLARE_METATYPE (ProcessingItem)
#endif // PROCESSINGITEM_H

111
README.md
View File

@ -1,92 +1,43 @@
# Screen Translator
[![Build Status](https://travis-ci.org/OneMoreGres/ScreenTranslator.svg)](https://travis-ci.org/OneMoreGres/ScreenTranslator.svg)
[![appveyor](https://img.shields.io/appveyor/ci/OneMoreGres/ScreenTranslator.svg)](https://img.shields.io/appveyor/ci/OneMoreGres/ScreenTranslator.svg)
**The project is almost abandoned. I don't have time for it and I can only fix minor issues**
## Introduction
Screen Translator
=================
Introduction
------------
This software allows you to translate any text on screen.
Basically it is a combination of screen capture, OCR and translation tools.
Translation is currently done via online services.
## Installation
Usage
-----
1. Press capture hotkey.
2. Select region on screen.
3. Get translation of recognized text.
**Windows**: download archive from [github releases](https://github.com/OneMoreGres/ScreenTranslator/releases) page, extract it and run `.exe` file.
Features
--------
* Many OCR languages (can be modified dynamically)
* Global hotkeys for main actions
* Copy last translation to clipboard
* Repeat last translation
* Show result in 2 ways (widget or tray baloon)
* Preprocess (scale) recognizeable image
* Interface languages (ru, eng)
If the app fails to start complaining about missing dlls or there are any update errors related to SSL/TLS then install or repair `vs_redist*.exe` from the release archive.
**Linux**: download `.AppImage` file from [github releases](https://github.com/OneMoreGres/ScreenTranslator/releases), make executable (`chmod +x <file>`) and run it.
Limitations
-----------
* Works only on primary screen
* Can not capture some dynamic web-pages
* Not very precise OCR
* Not all functions are cross-platform (may be bugged on some systems)
**OS X**: currently not supported.
### App translation
To install Hebrew translation of the app (thanks to [Y-PLONI](https://github.com/Y-PLONI)),
download [this](https://github.com/OneMoreGres/ScreenTranslator/releases/download/3.3.0/screentranslator_he.qm)
file and place it into the `translations` folder next to `screen-translator.exe`.
## Setup
The app doesn't have a main window.
After start it shows only the tray icon.
If the app detects invalid settings, it will show the error message via system tray.
It will also highlight the section name in red on the left panel of the settings window.
Clicking on that section name will show a more detailed error message in the right panel (also in red).
The packages downloaded from this site do not include resources, such as recognition language packs or scripts to interact with online translation services.
To download them, open the settings window and go to the `Update` section.
In the right panel, expand the `recognizers` and `translators` sections.
Select preferred items, then right click and choose `Install/Update`.
After the progress bar reaches `100%`, the resource's state will change to `Up to Date`.
You must download at least one `recognizers` resource and one `translators` resource.
After finishing downloads, go to the `Recognition` section and update the default recognition language setting (the source to be translated).
Then go to the `Translation` section, update the default translation language setting (the language to be translated into) and enable some or all translation sevices (you may also change their order by dragging).
After that all sections in the left panel should be black.
Then click `Ok` to close settings.
## Usage
1. Run program (note that it doesn't have main window).
2. Press capture hotkey.
3. Select region on screen. Customize it if needed.
4. Get translation of recognized text.
5. Check for updates if something is not working.
## FAQ
By default resources are downloaded to the one of the user's folders.
If `Portable` setting in `General` section is checked, then resources will be downloaded to the app's folder.
Set `QTWEBENGINE_DISABLE_SANDBOX=1` environment variable when fail to start due to crash.
Answers to some frequently asked questions can be found in issues or
[wiki](https://github.com/OneMoreGres/ScreenTranslator/wiki/FAQ)
## Limitations
* Can not capture some dynamic web-pages/full screen applications
## Dependencies
* see [Qt 5](https://qt-project.org/)
* see [Tesseract](https://github.com/tesseract-ocr/tesseract/)
* see [Leptonica](https://leptonica.com/)
Used software
-------------
* see [Qt 5](http://qt-project.org/)
* see [Tesseract](https://code.google.com/p/tesseract-ocr/)
* see [Leptonica](http://leptonica.com/) (Tesseract dependency)
* several online translation services
## Build from source
Look at the scripts (python3) in the `share/ci` folder.
Normally, you should only edit the `config.py` file.
Build dependencies at first, then build the app.
## Attributions
* icons made by
[Smashicons](https://www.flaticon.com/authors/smashicons),
[Freepik](https://www.flaticon.com/authors/freepik),
from [Flaticon](https://www.flaticon.com/)

93
Recognizer.cpp Normal file
View File

@ -0,0 +1,93 @@
#include "Recognizer.h"
#include <tesseract/baseapi.h>
#include <QDebug>
#include <QSettings>
#include "Settings.h"
#include "ImageProcessing.h"
#include "StAssert.h"
#include "RecognizerHelper.h"
Recognizer::Recognizer (QObject *parent) :
QObject (parent),
engine_ (NULL), recognizerHelper_ (new RecognizerHelper), imageScale_ (0) {
applySettings ();
}
void Recognizer::applySettings () {
QSettings settings;
settings.beginGroup (settings_names::recogntionGroup);
recognizerHelper_->load ();
tessDataDir_ = settings.value (settings_names::tessDataPlace,
settings_values::tessDataPlace).toString ();
if (tessDataDir_.right (1) != "/") {
tessDataDir_ += "/";
}
ocrLanguage_ = settings.value (settings_names::ocrLanguage,
settings_values::ocrLanguage).toString ();
imageScale_ = settings.value (settings_names::imageScale,
settings_values::imageScale).toInt ();
initEngine (engine_, ocrLanguage_);
}
bool Recognizer::initEngine (tesseract::TessBaseAPI * &engine, const QString &language) {
if (tessDataDir_.isEmpty () || language.isEmpty ()) {
emit error (tr ("Неверные параметры для OCR"));
return false;
}
if (engine != NULL) {
delete engine;
}
engine = new tesseract::TessBaseAPI ();
int result = engine->Init (qPrintable (tessDataDir_), qPrintable (language),
tesseract::OEM_DEFAULT);
if (result != 0) {
emit error (tr ("Ошибка инициализации OCR: %1").arg (result));
delete engine;
engine = NULL;
return false;
}
return true;
}
void Recognizer::recognize (ProcessingItem item) {
if (!item.isValid (true)) {
emit recognized (item);
return;
}
bool isCustomLanguage = (item.ocrLanguage != ocrLanguage_);
tesseract::TessBaseAPI *engine = (isCustomLanguage) ? NULL : engine_;
QString language = (isCustomLanguage) ? item.ocrLanguage : ocrLanguage_;
if (engine == NULL) {
if (!initEngine (engine, language)) {
emit recognized (item);
return;
}
}
Pix *image = prepareImage (item.source.toImage (), imageScale_);
ST_ASSERT (image != NULL);
engine->SetImage (image);
char *outText = engine->GetUTF8Text ();
engine->Clear ();
cleanupImage (&image);
QString result = QString (outText).trimmed ();
delete [] outText;
if (isCustomLanguage) {
delete engine;
}
if (!result.isEmpty ()) {
item.recognized = recognizerHelper_->substitute (result, language);
}
else {
emit error (tr ("Текст не распознан."));
}
emit recognized (item);
}

41
Recognizer.h Normal file
View File

@ -0,0 +1,41 @@
#ifndef RECOGNIZER_H
#define RECOGNIZER_H
#include <QObject>
#include "QPixmap"
#include "ProcessingItem.h"
namespace tesseract {
class TessBaseAPI;
}
class RecognizerHelper;
class Recognizer : public QObject {
Q_OBJECT
public:
explicit Recognizer (QObject *parent = 0);
signals:
void recognized (ProcessingItem item);
void error (QString text);
public slots:
void recognize (ProcessingItem item);
void applySettings ();
private:
bool initEngine (tesseract::TessBaseAPI * &engine, const QString &language);
private:
tesseract::TessBaseAPI *engine_;
RecognizerHelper *recognizerHelper_;
QString tessDataDir_;
QString ocrLanguage_;
int imageScale_;
};
#endif // RECOGNIZER_H

88
RecognizerHelper.cpp Normal file
View File

@ -0,0 +1,88 @@
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QSettings>
#include <QApplication>
#include "RecognizerHelper.h"
RecognizerHelper::RecognizerHelper ()
: fileName_ ("st_subs.csv") {
#ifdef Q_OS_LINUX
QDir settingDir = QFileInfo (QSettings ().fileName ()).dir ();
fileName_ = settingDir.absoluteFilePath (fileName_);
#else
fileName_ = QApplication::applicationDirPath () + QDir::separator () + fileName_;
#endif
}
void RecognizerHelper::load () {
subs_.clear ();
QFile f (fileName_);
if (!f.open (QFile::ReadOnly)) {
return;
}
QByteArray data = f.readAll ();
f.close ();
QStringList lines = QString::fromUtf8 (data).split ('\n', QString::SkipEmptyParts);
foreach (const QString &line, lines) {
QStringList parts = line.mid (1, line.size () - 2).split ("\",\""); // remove "
if (parts.size () < 3) {
continue;
}
subs_.append (Sub (parts[0], parts[1], parts[2]));
}
}
void RecognizerHelper::save () {
QFile f (fileName_);
if (!f.open (QFile::WriteOnly)) {
return;
}
foreach (const Sub &sub, subs_) {
QStringList parts = QStringList () << sub.language << sub.source << sub.target;
QString line = "\"" + parts.join ("\",\"") + "\"\n";
f.write (line.toUtf8 ());
}
f.close ();
}
QString RecognizerHelper::substitute (const QString &source, const QString &language) const {
QString result = source;
while (true) {
int bestMatchIndex = -1;
int bestMatchLen = 0;
int index = -1;
foreach (const Sub &sub, subs_) {
++index;
if (sub.language != language || !result.contains (sub.source)) {
continue;
}
int len = sub.source.length ();
if (len > bestMatchLen) {
bestMatchLen = len;
bestMatchIndex = index;
}
}
if (bestMatchIndex > -1) {
const Sub &sub = subs_.at (bestMatchIndex);
result.replace (sub.source, sub.target);
continue;
}
break;
}
return result;
}
const RecognizerHelper::Subs &RecognizerHelper::subs () const {
return subs_;
}
void RecognizerHelper::setSubs (const Subs &subs) {
subs_ = subs;
}
RecognizerHelper::Sub::Sub (const QString &language, const QString &source, const QString &target)
: language (language), source (source), target (target) {
}

33
RecognizerHelper.h Normal file
View File

@ -0,0 +1,33 @@
#ifndef RECOGNIZERHELPER_H
#define RECOGNIZERHELPER_H
#include <QString>
class RecognizerHelper {
public:
struct Sub {
Sub (const QString &language = QString (), const QString &source = QString (),
const QString &target = QString ());
QString language;
QString source;
QString target;
};
typedef QList<Sub> Subs;
public:
RecognizerHelper ();
void load ();
void save ();
QString substitute (const QString &source, const QString& language) const;
const Subs &subs () const;
void setSubs (const Subs &subs);
private:
QString fileName_;
Subs subs_;
};
#endif // RECOGNIZERHELPER_H

11
Recources.qrc Normal file
View File

@ -0,0 +1,11 @@
<RCC>
<qresource prefix="/">
<file>translations/translation_en.qm</file>
<file>translations/translation_ru.qm</file>
<file>images/STIconBlue.png</file>
<file>images/STIconGreen.png</file>
<file>images/STIconOrange.png</file>
<file>images/STIconRed.png</file>
<file>version.json</file>
</qresource>
</RCC>

121
ResultDialog.cpp Normal file
View File

@ -0,0 +1,121 @@
#include "ResultDialog.h"
#include "ui_ResultDialog.h"
#include "StAssert.h"
#include "LanguageHelper.h"
#include <QDesktopWidget>
#include <QMouseEvent>
#include <QMenu>
ResultDialog::ResultDialog (const LanguageHelper &dictionary, QWidget *parent) :
QDialog (parent),
ui (new Ui::ResultDialog),
dictionary_ (dictionary),
contextMenu_ (NULL), recognizeSubMenu_ (NULL), translateSubMenu_ (NULL),
clipboardAction_ (NULL), imageClipboardAction_ (NULL), correctAction_ (NULL) {
ui->setupUi (this);
setWindowFlags (Qt::FramelessWindowHint | Qt::NoDropShadowWindowHint |
Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint);
QString styleSheet =
"#recognizeLabel, #translateLabel {"
"color: black;"
"background: qlineargradient(x1:0, y1:0, x2:1, y2:1,"
"stop:0 darkGray, stop: 0.5 lightGray, stop:1 darkGray);"
"}";
setStyleSheet (styleSheet);
installEventFilter (this);
createContextMenu ();
applySettings ();
}
ResultDialog::~ResultDialog () {
delete contextMenu_;
delete ui;
}
const ProcessingItem &ResultDialog::item () const {
return item_;
}
void ResultDialog::applySettings () {
dictionary_.updateMenu (recognizeSubMenu_, dictionary_.availableOcrLanguagesUi ());
dictionary_.updateMenu (translateSubMenu_, dictionary_.translateLanguagesUi ());
}
void ResultDialog::createContextMenu () {
contextMenu_ = new QMenu ();
recognizeSubMenu_ = contextMenu_->addMenu (tr ("Распознать другой язык"));
translateSubMenu_ = contextMenu_->addMenu (tr ("Перевести на другой язык"));
clipboardAction_ = contextMenu_->addAction (tr ("Скопировать в буфер"));
imageClipboardAction_ = contextMenu_->addAction (tr ("Скопировать рисунок в буфер"));
correctAction_ = contextMenu_->addAction (tr ("Исправить распознанный текст"));
}
bool ResultDialog::eventFilter (QObject *object, QEvent *event) {
Q_UNUSED (object);
if (event->type () == QEvent::MouseButtonPress) {
Qt::MouseButton button = static_cast<QMouseEvent *>(event)->button ();
if (button == Qt::RightButton) {
QAction *action = contextMenu_->exec (QCursor::pos ());
if (recognizeSubMenu_->findChildren<QAction *> ().contains (action)) {
ProcessingItem item = item_;
item.translated = item.recognized = QString ();
item.ocrLanguage = dictionary_.ocrUiToCode (action->text ());
emit requestRecognize (item);
}
else if (translateSubMenu_->findChildren<QAction *> ().contains (action)) {
ProcessingItem item = item_;
item.translated.clear ();
item.translateLanguage = dictionary_.translateUiToCode (action->text ());
emit requestTranslate (item);
}
else if (action == clipboardAction_) {
emit requestClipboard ();
}
else if (action == imageClipboardAction_) {
emit requestImageClipboard ();
}
else if (action == correctAction_) {
emit requestEdition (item_);
// Return because Manager calls showResult() before hide() otherwise.
return QDialog::eventFilter (object, event);
}
}
hide ();
}
else if (event->type () == QEvent::WindowDeactivate) {
hide ();
}
return QDialog::eventFilter (object, event);
}
void ResultDialog::showResult (ProcessingItem item) {
ST_ASSERT (item.isValid ());
item_ = item;
ui->sourceLabel->setPixmap (item.source);
ui->recognizeLabel->setText (item.recognized);
ui->translateLabel->setText (item.translated);
bool gotTranslation = !item.translated.isEmpty ();
ui->translateLabel->setVisible (gotTranslation);
ui->translateLine->setVisible (gotTranslation);
show ();
adjustSize ();
#ifdef Q_OS_LINUX
hide (); // buggy otherwise (on some systems)
show ();
#endif
QDesktopWidget *desktop = QApplication::desktop ();
Q_CHECK_PTR (desktop);
QPoint correction = QPoint ((width () - item.source.width ()) / 2, ui->frame->lineWidth ());
move (item.screenPos - correction);
QRect screenRect = desktop->screenGeometry (this);
int minY = screenRect.bottom () - height ();
if (y () > minY) {
move (x (), minY);
}
activateWindow ();
}

51
ResultDialog.h Normal file
View File

@ -0,0 +1,51 @@
#ifndef RESULTDIALOG_H
#define RESULTDIALOG_H
#include <QDialog>
#include <QMenu>
#include "ProcessingItem.h"
namespace Ui {
class ResultDialog;
}
class LanguageHelper;
class ResultDialog : public QDialog {
Q_OBJECT
public:
explicit ResultDialog (const LanguageHelper &dictionary, QWidget *parent = 0);
~ResultDialog ();
signals:
void requestRecognize (ProcessingItem item);
void requestTranslate (ProcessingItem item);
void requestClipboard (); // Assume that slot will be called immediately.
void requestImageClipboard (); // Assume that slot will be called immediately.
void requestEdition (ProcessingItem item);
public:
const ProcessingItem &item () const;
bool eventFilter (QObject *object, QEvent *event);
public slots:
void showResult (ProcessingItem item);
void applySettings ();
private:
void createContextMenu ();
private:
Ui::ResultDialog *ui;
const LanguageHelper &dictionary_;
QMenu *contextMenu_;
QMenu *recognizeSubMenu_;
QMenu *translateSubMenu_;
QAction *clipboardAction_;
QAction *imageClipboardAction_;
QAction *correctAction_;
ProcessingItem item_;
};
#endif // RESULTDIALOG_H

116
ResultDialog.ui Normal file
View File

@ -0,0 +1,116 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ResultDialog</class>
<widget class="QDialog" name="ResultDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>260</width>
<height>222</height>
</rect>
</property>
<property name="windowTitle">
<string>Результат</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<property name="spacing">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QFrame" name="frame">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<property name="spacing">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="sourceLabel">
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="Line" name="recognizeLine">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="recognizeLabel">
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="Line" name="translateLine">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="translateLabel">
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

92
ScreenTranslator.pro Normal file
View File

@ -0,0 +1,92 @@
#-------------------------------------------------
#
# Project created by QtCreator 2013-11-22T12:00:23
#
#-------------------------------------------------
QT += core gui network webkitwidgets
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = ScreenTranslator
TEMPLATE = app
CONFIG += c++11
win32{
INCLUDEPATH += $$PWD/../build/mingw/deps/include
LIBS += -L$$PWD/../build/mingw/deps/lib -lUser32 -lws2_32
}
linux{
QT += x11extras
INCLUDEPATH += $$PWD/../build/linux/deps/include
LIBS += -L$$PWD/../build/linux/deps/lib -lX11 -Wl,-rpath,.
}
LIBS += -ltesseract -llept
include(3rd-party/qtsingleapplication/qtsingleapplication.pri)
SOURCES += main.cpp\
Manager.cpp \
SettingsEditor.cpp \
SelectionDialog.cpp \
GlobalActionHelper.cpp \
Recognizer.cpp \
ResultDialog.cpp \
ProcessingItem.cpp \
ImageProcessing.cpp \
LanguageHelper.cpp \
WebTranslator.cpp \
WebTranslatorProxy.cpp \
TranslatorHelper.cpp \
RecognizerHelper.cpp \
Utils.cpp \
Updater.cpp
HEADERS += \
Manager.h \
SettingsEditor.h \
SelectionDialog.h \
GlobalActionHelper.h \
Recognizer.h \
Settings.h \
ProcessingItem.h \
ResultDialog.h \
ImageProcessing.h \
LanguageHelper.h \
WebTranslator.h \
WebTranslatorProxy.h \
StAssert.h \
TranslatorHelper.h \
RecognizerHelper.h \
Utils.h \
Updater.h
FORMS += \
SettingsEditor.ui \
SelectionDialog.ui \
ResultDialog.ui
RESOURCES += \
Recources.qrc
TRANSLATIONS += \
translations/translation_en.ts \
translations/translation_ru.ts
OTHER_FILES += \
images/* \
translators/* \
scripts/* \
distr/* \
version.json \
README.md \
uncrustify.cfg\
.travis.yml \
TODO.md
QMAKE_TARGET_COMPANY = Gres
QMAKE_TARGET_PRODUCT = Screen Translator
QMAKE_TARGET_COPYRIGHT = Copyright (c) Gres
VERSION = 2.0.0.0
RC_ICONS = images/icon.ico

122
SelectionDialog.cpp Normal file
View File

@ -0,0 +1,122 @@
#include "SelectionDialog.h"
#include "ui_SelectionDialog.h"
#include "LanguageHelper.h"
#include "StAssert.h"
#include <QMouseEvent>
#include <QPainter>
#include <QDebug>
#include <QMenu>
SelectionDialog::SelectionDialog (const LanguageHelper &dictionary, QWidget *parent) :
QDialog (parent),
ui (new Ui::SelectionDialog), dictionary_ (dictionary),
languageMenu_ (new QMenu), swapLanguagesAction_ (NULL) {
ui->setupUi (this);
setWindowFlags (Qt::FramelessWindowHint | Qt::NoDropShadowWindowHint |
Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint);
ui->label->setAutoFillBackground (false);
ui->label->installEventFilter (this);
applySettings ();
}
SelectionDialog::~SelectionDialog () {
delete languageMenu_;
delete ui;
}
void SelectionDialog::applySettings () {
dictionary_.updateMenu (languageMenu_, dictionary_.availableOcrLanguagesUi ());
if (!languageMenu_->isEmpty ()) {
swapLanguagesAction_ = languageMenu_->addAction (tr ("Поменять язык текста и перевода"));
}
}
bool SelectionDialog::eventFilter (QObject *object, QEvent *event) {
if (object != ui->label) {
return QDialog::eventFilter (object, event);
}
if (event->type () == QEvent::Show) {
startSelectPos_ = currentSelectPos_ = QPoint ();
}
else if (event->type () == QEvent::MouseButtonPress) {
QMouseEvent *mouseEvent = static_cast <QMouseEvent *> (event);
if ((mouseEvent->button () == Qt::LeftButton ||
mouseEvent->button () == Qt::RightButton) && startSelectPos_.isNull ()) {
startSelectPos_ = mouseEvent->pos ();
}
}
else if (event->type () == QEvent::MouseMove) {
QMouseEvent *mouseEvent = static_cast <QMouseEvent *> (event);
if ((mouseEvent->buttons () & Qt::LeftButton ||
mouseEvent->buttons () & Qt::RightButton) && !startSelectPos_.isNull ()) {
currentSelectPos_ = mouseEvent->pos ();
ui->label->repaint ();
}
}
else if (event->type () == QEvent::Paint) {
QRect selection = QRect (startSelectPos_, currentSelectPos_).normalized ();
if (selection.isValid ()) {
QPainter painter (ui->label);
painter.setPen (Qt::red);
painter.drawRect (selection);
}
}
else if (event->type () == QEvent::MouseButtonRelease) {
QMouseEvent *mouseEvent = static_cast <QMouseEvent *> (event);
if (mouseEvent->button () == Qt::LeftButton ||
mouseEvent->button () == Qt::RightButton) {
if (startSelectPos_.isNull () || currentPixmap_.isNull ()) {
return QDialog::eventFilter (object, event);
}
QPoint endPos = mouseEvent->pos ();
QRect selection = QRect (startSelectPos_, endPos).normalized ();
startSelectPos_ = currentSelectPos_ = QPoint ();
QPixmap selectedPixmap = currentPixmap_.copy (selection);
if (selectedPixmap.width () < 3 || selectedPixmap.height () < 3) {
reject ();
return QDialog::eventFilter (object, event);
}
ProcessingItem item;
item.source = selectedPixmap;
item.screenPos = pos () + selection.topLeft ();
item.modifiers = mouseEvent->modifiers ();
if (mouseEvent->button () == Qt::RightButton &&
!languageMenu_->children ().isEmpty ()) {
QAction *action = languageMenu_->exec (QCursor::pos ());
if (action == NULL) {
reject ();
return QDialog::eventFilter (object, event);
}
if (action == swapLanguagesAction_) {
item.swapLanguages_ = true;
}
else {
item.ocrLanguage = dictionary_.ocrUiToCode (action->text ());
ST_ASSERT (!item.ocrLanguage.isEmpty ());
item.sourceLanguage = dictionary_.ocrToTranslateCodes (item.ocrLanguage);
ST_ASSERT (!item.sourceLanguage.isEmpty ());
}
}
emit selected (item);
}
}
return QDialog::eventFilter (object, event);
}
void SelectionDialog::setPixmap (QPixmap pixmap, const QRect &showGeometry) {
ST_ASSERT (!pixmap.isNull ());
ST_ASSERT (!showGeometry.isEmpty ());
currentPixmap_ = pixmap;
QPalette palette = this->palette ();
palette.setBrush (this->backgroundRole (), pixmap);
this->setPalette (palette);
this->setGeometry (showGeometry);
show ();
activateWindow ();
}

43
SelectionDialog.h Normal file
View File

@ -0,0 +1,43 @@
#ifndef SELECTIONDIALOG_H
#define SELECTIONDIALOG_H
#include <QDialog>
#include <QPixmap>
#include <QMenu>
#include "ProcessingItem.h"
namespace Ui {
class SelectionDialog;
}
class LanguageHelper;
class SelectionDialog : public QDialog {
Q_OBJECT
public:
explicit SelectionDialog (const LanguageHelper &dictionary, QWidget *parent = 0);
~SelectionDialog ();
bool eventFilter (QObject *object, QEvent *event);
signals:
void selected (ProcessingItem pixmap);
void nothingSelected ();
public slots:
//! Show pixmap with given geometry.
void setPixmap (QPixmap pixmap, const QRect &showGeometry);
void applySettings ();
private:
Ui::SelectionDialog *ui;
const LanguageHelper &dictionary_;
QPoint startSelectPos_;
QPoint currentSelectPos_;
QPixmap currentPixmap_;
QMenu *languageMenu_;
QAction *swapLanguagesAction_;
};
#endif // SELECTIONDIALOG_H

43
SelectionDialog.ui Normal file
View File

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SelectionDialog</class>
<widget class="QDialog" name="SelectionDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="cursor">
<cursorShape>CrossCursor</cursorShape>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

81
Settings.h Normal file
View File

@ -0,0 +1,81 @@
#ifndef SETTINGS_H
#define SETTINGS_H
#include <QString>
namespace settings_names {
//! UI
const QString guiGroup = "GUI";
const QString geometry = "geometry";
const QString captureHotkey = "captureHotkey";
const QString repeatCaptureHotkey = "repeatCaptureHotkey";
const QString repeatHotkey = "repeatHotkey";
const QString clipboardHotkey = "clipboardHotkey";
const QString resultShowType = "resultShowType";
const QString proxyType = "proxyType";
const QString proxyHostName = "proxyHostName";
const QString proxyPort = "proxyPort";
const QString proxyUser = "proxyUser";
const QString proxyPassword = "proxyPassword";
const QString proxySavePassword = "proxySavePassword";
const QString autoUpdateType = "autoUpdateType";
const QString lastUpdateCheck = "lastUpdateCheck";
//! Recognition
const QString recogntionGroup = "Recognition";
const QString tessDataPlace = "tessdata_dir";
const QString ocrLanguage = "language";
const QString imageScale = "image_scale";
//! Translation
const QString translationGroup = "Translation";
const QString doTranslation = "doTranslation";
const QString ignoreSslErrors = "ignoreSslErrors";
const QString forceRotateTranslators = "forceRotateTranslators";
const QString sourceLanguage = "source_language";
const QString translationLanguage = "translation_language";
const QString translationTimeout = "translation_timeout";
const QString translationDebugMode = "translation_debug";
const QString translators = "translators";
}
namespace settings_values {
const QString appName = "ScreenTranslator";
const QString companyName = "Gres";
//! UI
const QString captureHotkey = "Ctrl+Alt+Z";
const QString repeatCaptureHotkey = "Ctrl+Alt+S";
const QString repeatHotkey = "Ctrl+Alt+X";
const QString clipboardHotkey = "Ctrl+Alt+C";
const QString resultShowType = "1";//dialog
const int proxyType = 0;
const QString proxyHostName = "";
const int proxyPort = 8080;
const QString proxyUser = "";
const QString proxyPassword = "";
const bool proxySavePassword = false;
const int autoUpdateType = 0; //Never
const QString lastUpdateCheck = "";
//! Recognition
#if defined(Q_OS_LINUX)
const QString tessDataPlace = "/usr/share/tesseract-ocr/";
#else
const QString tessDataPlace = "./";
#endif
const QString ocrLanguage = "eng";
const int imageScale = 5;
//! Translation
const bool doTranslation = true;
const bool ignoreSslErrors = false;
const bool forceRotateTranslators = false;
const QString sourceLanguage = "auto";
const QString translationLanguage = "ru";
const int translationTimeout = 15; // secs
const bool translationDebugMode = false;
const QString translators = "";
}
#endif // SETTINGS_H

292
SettingsEditor.cpp Normal file
View File

@ -0,0 +1,292 @@
#include "SettingsEditor.h"
#include "ui_SettingsEditor.h"
#include "LanguageHelper.h"
#include "TranslatorHelper.h"
#include "RecognizerHelper.h"
#include "StAssert.h"
#include "Utils.h"
#include <QSettings>
#include <QFileDialog>
#include <QDir>
#include <QRegExpValidator>
#include <QNetworkProxy>
#include "Settings.h"
SettingsEditor::SettingsEditor (const LanguageHelper &dictionary, QWidget *parent) :
QDialog (parent),
ui (new Ui::SettingsEditor), translatorHelper_ (new TranslatorHelper),
recognizerHelper_ (new RecognizerHelper), dictionary_ (dictionary),
buttonGroup_ (new QButtonGroup (this)) {
ui->setupUi (this);
buttonGroup_->addButton (ui->trayRadio, 0);
buttonGroup_->addButton (ui->dialogRadio, 1);
connect (ui->updateButton, SIGNAL (clicked (bool)), SIGNAL (updateCheckRequested ()));
QStringList updateTypes = QStringList () << tr ("Никогда") << tr ("Ежедневно")
<< tr ("Еженедельно") << tr ("Ежемесячно");
ui->updateCombo->addItems (updateTypes);
connect (ui->tessdataButton, SIGNAL (clicked ()), SLOT (openTessdataDialog ()));
connect (ui->tessdataEdit, SIGNAL (textChanged (const QString &)),
SLOT (initOcrLangCombo (const QString &)));
connect (ui->recognizerFixTable, SIGNAL (itemChanged (QTableWidgetItem *)),
SLOT (recognizerFixTableItemChanged (QTableWidgetItem *)));
ui->translateLangCombo->addItems (dictionary_.translateLanguagesUi ());
typedef QNetworkProxy::ProxyType ProxyType;
QMap<ProxyType, QString> proxyTypeNames;
proxyTypeNames.insert (QNetworkProxy::NoProxy, tr ("Нет"));
proxyTypeNames.insert (QNetworkProxy::Socks5Proxy, tr ("SOCKS 5"));
proxyTypeNames.insert (QNetworkProxy::HttpProxy, tr ("HTTP"));
QList<int> proxyOrder = proxyTypeOrder ();
foreach (int type, proxyOrder) {
ui->proxyTypeCombo->addItem (proxyTypeNames.value (QNetworkProxy::ProxyType (type)));
}
QRegExp urlRegexp (R"(^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$)");
ui->proxyHostEdit->setValidator (new QRegExpValidator (urlRegexp, ui->proxyHostEdit));
ui->proxyPassEdit->setEchoMode (QLineEdit::PasswordEchoOnEdit);
loadSettings ();
loadState ();
}
SettingsEditor::~SettingsEditor () {
saveState ();
delete recognizerHelper_;
delete translatorHelper_;
delete ui;
}
void SettingsEditor::done (int result) {
if (result == QDialog::Accepted) {
saveSettings ();
emit settingsEdited ();
}
QDialog::done (result);
}
void SettingsEditor::saveSettings () const {
using namespace settings_names;
QSettings settings;
settings.beginGroup (guiGroup);
settings.setValue (captureHotkey, ui->captureEdit->keySequence ().toString ());
settings.setValue (repeatCaptureHotkey, ui->repeatCaptureEdit->keySequence ().toString ());
settings.setValue (repeatHotkey, ui->repeatEdit->keySequence ().toString ());
settings.setValue (clipboardHotkey, ui->clipboardEdit->keySequence ().toString ());
settings.setValue (resultShowType, buttonGroup_->checkedId ());
settings.setValue (proxyType, ui->proxyTypeCombo->currentIndex ());
settings.setValue (proxyHostName, ui->proxyHostEdit->text ());
settings.setValue (proxyPort, ui->proxyPortSpin->value ());
settings.setValue (proxyUser, ui->proxyUserEdit->text ());
if (ui->proxySaveCheck->isChecked ()) {
settings.setValue (proxyPassword, encode (ui->proxyPassEdit->text ()));
}
else {
settings.remove (proxyPassword);
QNetworkProxy proxy = QNetworkProxy::applicationProxy ();
proxy.setPassword (ui->proxyPassEdit->text ());
QNetworkProxy::setApplicationProxy (proxy);
}
settings.setValue (proxySavePassword, ui->proxySaveCheck->isChecked ());
settings.setValue (autoUpdateType, ui->updateCombo->currentIndex ());
settings.endGroup ();
settings.beginGroup (recogntionGroup);
settings.setValue (tessDataPlace, ui->tessdataEdit->text ());
QString ocrLanguageVal = dictionary_.ocrUiToCode (ui->ocrLangCombo->currentText ());
settings.setValue (ocrLanguage, ocrLanguageVal);
settings.setValue (imageScale, ui->imageScaleSpin->value ());
{ //Recognizer substitutions
RecognizerHelper::Subs subs;
QTableWidget *t = ui->recognizerFixTable; // Shortcut
for (int i = 0, end = t->rowCount () - 1; i < end; ++i) {
QComboBox *combo = static_cast<QComboBox *>(t->cellWidget (i, SubsColLanguage));
QString langUi = combo->currentText ();
RecognizerHelper::Sub sub;
sub.language = dictionary_.ocrUiToCode (langUi);
#define GET(COL) (t->item (i, COL) ? t->item (i, COL)->text () : QString ())
sub.source = GET (SubsColSource);
sub.target = GET (SubsColTarget);
#undef GET
if (langUi.isEmpty () || sub.language == langUi || sub.source.isEmpty ()) {
continue;
}
subs.append (sub);
}
recognizerHelper_->setSubs (subs);
recognizerHelper_->save ();
}
settings.endGroup ();
settings.beginGroup (translationGroup);
settings.setValue (doTranslation, ui->doTranslationCheck->isChecked ());
settings.setValue (ignoreSslErrors, ui->ignoreSslCheck->isChecked ());
settings.setValue (forceRotateTranslators, ui->forceRotateCheck->isChecked ());
settings.setValue (translationDebugMode, ui->translatorDebugCheck->isChecked ());
QString trLanguage = dictionary_.translateUiToCode (ui->translateLangCombo->currentText ());
settings.setValue (translationLanguage, trLanguage);
QString sourceLanguageVal = dictionary_.ocrToTranslateCodes (ocrLanguage);
settings.setValue (sourceLanguage, sourceLanguageVal);
settings.setValue (translationTimeout, ui->translateTimeoutSpin->value ());
{//Translators
QStringList enabled;
for (int i = 0, end = ui->translatorList->count (); i < end; ++i) {
QListWidgetItem *item = ui->translatorList->item (i);
if (item->checkState () == Qt::Checked) {
enabled << item->text ();
}
}
translatorHelper_->setEnabledTranslators (enabled);
}
settings.endGroup ();
}
void SettingsEditor::openTessdataDialog () {
QString path = QFileDialog::getExistingDirectory (this, tr ("Путь к tessdata"));
if (path.isEmpty ()) {
return;
}
QDir dir (path);
if (dir.dirName () == QString ("tessdata")) {
dir.cdUp ();
}
ui->tessdataEdit->setText (dir.path ());
}
void SettingsEditor::loadSettings () {
#define GET(FIELD) settings.value (settings_names::FIELD, settings_values::FIELD)
QSettings settings;
settings.beginGroup (settings_names::guiGroup);
ui->captureEdit->setKeySequence (QKeySequence (GET (captureHotkey).toString ()));
ui->repeatCaptureEdit->setKeySequence (QKeySequence (GET (repeatCaptureHotkey).toString ()));
ui->repeatEdit->setKeySequence (QKeySequence (GET (repeatHotkey).toString ()));
ui->clipboardEdit->setKeySequence (QKeySequence (GET (clipboardHotkey).toString ()));
QAbstractButton *button = buttonGroup_->button (GET (resultShowType).toInt ());
Q_CHECK_PTR (button);
button->setChecked (true);
ui->proxyTypeCombo->setCurrentIndex (GET (proxyType).toInt ());
ui->proxyHostEdit->setText (GET (proxyHostName).toString ());
ui->proxyPortSpin->setValue (GET (proxyPort).toInt ());
ui->proxyUserEdit->setText (GET (proxyUser).toString ());
ui->proxySaveCheck->setChecked (GET (proxySavePassword).toBool ());
if (ui->proxySaveCheck->isChecked ()) {
ui->proxyPassEdit->setText (encode (GET (proxyPassword).toString ()));
}
else {
ui->proxyPassEdit->setText (QNetworkProxy::applicationProxy ().password ());
}
ui->updateCombo->setCurrentIndex (GET (autoUpdateType).toInt ());
settings.endGroup ();
settings.beginGroup (settings_names::recogntionGroup);
ui->tessdataEdit->setText (GET (tessDataPlace).toString ());
QString ocrLanguage = dictionary_.ocrCodeToUi (GET (ocrLanguage).toString ());
ui->ocrLangCombo->setCurrentText (ocrLanguage);
ui->imageScaleSpin->setValue (GET (imageScale).toInt ());
{//Recognizer substitutions
recognizerHelper_->load ();
RecognizerHelper::Subs subs = recognizerHelper_->subs ();
ui->recognizerFixTable->setRowCount (subs.size ());
int row = 0;
foreach (const RecognizerHelper::Sub & sub, subs) {
if (!initSubsTableRow (row, sub.language)) {
continue;
}
ui->recognizerFixTable->setItem (row, SubsColSource, new QTableWidgetItem (sub.source));
ui->recognizerFixTable->setItem (row, SubsColTarget, new QTableWidgetItem (sub.target));
++row;
}
ui->recognizerFixTable->setRowCount (row + 1);
initSubsTableRow (row);
ui->recognizerFixTable->resizeColumnsToContents ();
}
settings.endGroup ();
settings.beginGroup (settings_names::translationGroup);
ui->doTranslationCheck->setChecked (GET (doTranslation).toBool ());
ui->ignoreSslCheck->setChecked (GET (ignoreSslErrors).toBool ());
ui->forceRotateCheck->setChecked (GET (forceRotateTranslators).toBool ());
ui->translatorDebugCheck->setChecked (GET (translationDebugMode).toBool ());
QString trLanguage = dictionary_.translateCodeToUi (GET (translationLanguage).toString ());
ui->translateLangCombo->setCurrentText (trLanguage);
ui->translateTimeoutSpin->setValue (GET (translationTimeout).toInt ());
{// Translators
QStringList enabled;
ui->translatorList->addItems (translatorHelper_->possibleTranslators (enabled));
for (int i = 0, end = ui->translatorList->count (); i < end; ++i) {
QListWidgetItem *item = ui->translatorList->item (i);
Qt::CheckState state = enabled.contains (item->text ()) ? Qt::Checked : Qt::Unchecked;
item->setCheckState (state);
}
}
settings.endGroup ();
#undef GET
}
bool SettingsEditor::initSubsTableRow (int row, const QString &languageCode) {
QString lang = dictionary_.ocrCodeToUi (languageCode);
if (!languageCode.isEmpty () && lang == languageCode) {
return false;
}
QComboBox *langCombo = new QComboBox (ui->recognizerFixTable);
langCombo->setModel (ui->ocrLangCombo->model ());
if (!languageCode.isEmpty ()) {
langCombo->setCurrentText (lang);
}
else {
langCombo->setCurrentIndex (ui->ocrLangCombo->currentIndex ());
}
ui->recognizerFixTable->setCellWidget (row, SubsColLanguage, langCombo);
return true;
}
void SettingsEditor::saveState () const {
QSettings settings;
settings.beginGroup (settings_names::guiGroup);
settings.setValue (objectName () + "_" + settings_names::geometry, saveGeometry ());
}
void SettingsEditor::loadState () {
QSettings settings;
settings.beginGroup (settings_names::guiGroup);
restoreGeometry (settings.value (objectName () + "_" + settings_names::geometry).toByteArray ());
}
void SettingsEditor::initOcrLangCombo (const QString &path) {
ui->ocrLangCombo->clear ();
ui->ocrLangCombo->addItems (dictionary_.availableOcrLanguagesUi (path));
}
void SettingsEditor::recognizerFixTableItemChanged (QTableWidgetItem *item) {
ST_ASSERT (item->column () < 3);
int row = item->row ();
QTableWidget *t = ui->recognizerFixTable;
#define CHECK(COL) (!t->item (row, COL) || t->item (row, COL)->text ().isEmpty ())
bool isRowEmpty = CHECK (SubsColSource) && CHECK (SubsColTarget);
#undef CHECK
int lastRow = ui->recognizerFixTable->rowCount () - 1;
if (isRowEmpty && row != lastRow) {
ui->recognizerFixTable->removeRow (row);
}
else if (!isRowEmpty && row == lastRow) {
int newRow = lastRow + 1;
ui->recognizerFixTable->insertRow (newRow);
initSubsTableRow (newRow);
}
}

54
SettingsEditor.h Normal file
View File

@ -0,0 +1,54 @@
#ifndef SETTINGSEDITOR_H
#define SETTINGSEDITOR_H
#include <QDialog>
#include <QButtonGroup>
#include <QMap>
class QTableWidgetItem;
namespace Ui {
class SettingsEditor;
}
class LanguageHelper;
class TranslatorHelper;
class RecognizerHelper;
class SettingsEditor : public QDialog {
Q_OBJECT
enum SubsCol {
SubsColLanguage = 0, SubsColSource, SubsColTarget
};
public:
explicit SettingsEditor (const LanguageHelper &dictionary, QWidget *parent = 0);
~SettingsEditor ();
signals:
void settingsEdited ();
void updateCheckRequested ();
public slots:
void done (int result);
private slots:
void saveSettings () const;
void openTessdataDialog ();
void initOcrLangCombo (const QString &path);
void recognizerFixTableItemChanged (QTableWidgetItem *item);
private:
void loadSettings ();
void saveState () const;
void loadState ();
bool initSubsTableRow (int row, const QString &languageCode = QString ());
private:
Ui::SettingsEditor *ui;
TranslatorHelper *translatorHelper_;
RecognizerHelper *recognizerHelper_;
const LanguageHelper &dictionary_;
QButtonGroup *buttonGroup_;
};
#endif // SETTINGSEDITOR_H

530
SettingsEditor.ui Normal file
View File

@ -0,0 +1,530 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SettingsEditor</class>
<widget class="QDialog" name="SettingsEditor">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>553</width>
<height>483</height>
</rect>
</property>
<property name="windowTitle">
<string>Настройки</string>
</property>
<layout class="QGridLayout" name="gridLayout_6">
<item row="1" column="0" colspan="2">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="commonTab">
<attribute name="title">
<string>Общее</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_8">
<item row="0" column="0">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Горячие клавиши</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Сочетание клавиш для перехода в режим захвата.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Захватить</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QKeySequenceEdit" name="captureEdit"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_8">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Сочетание клавиш для перехода в режим захвата, но с использованием последнего использованного, а не текущего, изображения.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Захватить повторно</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QKeySequenceEdit" name="repeatCaptureEdit"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Сочетание клавиш для повторного отображения последнего результата.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Показать</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QKeySequenceEdit" name="repeatEdit"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_7">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Сочетание клавиш для копирования последнего результата в буфер обмена.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Скопировать</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QKeySequenceEdit" name="clipboardEdit"/>
</item>
</layout>
</widget>
</item>
<item row="1" column="0">
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Прокси</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
<string>Тип:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="proxyTypeCombo"/>
</item>
<item row="0" column="2">
<widget class="QLabel" name="label_15">
<property name="text">
<string>Пользователь:</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QLineEdit" name="proxyUserEdit"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_13">
<property name="text">
<string>Адрес:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="proxyHostEdit"/>
</item>
<item row="1" column="2">
<widget class="QLabel" name="label_16">
<property name="text">
<string>Пароль:</string>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QLineEdit" name="proxyPassEdit"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_14">
<property name="text">
<string>Порт:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="proxyPortSpin">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>65535</number>
</property>
</widget>
</item>
<item row="2" column="2" colspan="2">
<widget class="QCheckBox" name="proxySaveCheck">
<property name="text">
<string>Сохранять пароль (небезопасно)</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="2" column="0">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QGroupBox" name="resultGroup">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Вывод результата</string>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0">
<widget class="QRadioButton" name="trayRadio">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Трей</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QRadioButton" name="dialogRadio">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Окно</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>Обновление</string>
</property>
<layout class="QGridLayout" name="gridLayout_5">
<item row="0" column="0">
<widget class="QLabel" name="label_17">
<property name="text">
<string>Проверять обновления:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="updateCombo"/>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="updateButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Проверить</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item row="3" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>270</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="recognizeTab">
<attribute name="title">
<string>Распознавание</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Необходимо для распознавания.&lt;/p&gt;&lt;p&gt;Скачивается отсюда: &lt;a href=&quot;https://github.com/tesseract-ocr/tessdata&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#7593bc;&quot;&gt;https://github.com/tesseract-ocr/tessdata&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&amp;quot;./&amp;quot; означает, что папка &amp;quot;tessdata&amp;quot; находится в одной директории с исполняемым файлом программы.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Путь к tessdata</string>
</property>
<property name="buddy">
<cstring>tessdataEdit</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="tessdataEdit"/>
</item>
<item row="0" column="2">
<widget class="QToolButton" name="tessdataButton">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_4">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Заполняется на основании содержания tessdata&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Язык распознавания</string>
</property>
<property name="buddy">
<cstring>ocrLangCombo</cstring>
</property>
</widget>
</item>
<item row="1" column="1" colspan="2">
<widget class="QComboBox" name="ocrLangCombo"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_5">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Масштабирование изображения для улучшения распознания. Больше - лучше (до определенных пределов), но медленнее и потребляет больше памяти.&lt;/p&gt;&lt;p&gt;Рекомендуемые значения от 5 до 10.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Увеличение масштаба</string>
</property>
<property name="buddy">
<cstring>imageScaleSpin</cstring>
</property>
</widget>
</item>
<item row="2" column="1" colspan="2">
<widget class="QSpinBox" name="imageScaleSpin"/>
</item>
<item row="3" column="0" colspan="3">
<widget class="QLabel" name="label_11">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Символы, регулярно распознаваемые с ошибками. При обнаружении будут заменены на указанные.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Исправления:</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="4" column="0" colspan="3">
<widget class="QTableWidget" name="recognizerFixTable">
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<column>
<property name="text">
<string>Язык</string>
</property>
</column>
<column>
<property name="text">
<string>Исходный текст</string>
</property>
</column>
<column>
<property name="text">
<string>Исправление</string>
</property>
</column>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="translateTab">
<attribute name="title">
<string>Перевод</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_7">
<item row="0" column="0">
<widget class="QCheckBox" name="doTranslationCheck">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Необходимо ли переводить (вкл) распознанный текст.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Переводить текст</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_9">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Максимальное время, которое может быть затрачено на перевод, чтобы он не считался &amp;quot;зависшим&amp;quot;.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Максимальное время перевода:</string>
</property>
</widget>
</item>
<item row="3" column="1" colspan="2">
<widget class="QSpinBox" name="translateTimeoutSpin">
<property name="suffix">
<string> сек.</string>
</property>
</widget>
</item>
<item row="4" column="1" colspan="2">
<widget class="QComboBox" name="translateLangCombo"/>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_6">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Язык, на который осуществляется перевод.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Язык результата:</string>
</property>
<property name="buddy">
<cstring>translateLangCombo</cstring>
</property>
</widget>
</item>
<item row="5" column="0" colspan="3">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Переводчики:</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="6" column="0" colspan="3">
<widget class="QListWidget" name="translatorList">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Отображены в порядке убывания приоритета.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="dragDropMode">
<enum>QAbstractItemView::InternalMove</enum>
</property>
<property name="defaultDropAction">
<enum>Qt::MoveAction</enum>
</property>
</widget>
</item>
<item row="0" column="1" colspan="2">
<widget class="QCheckBox" name="translatorDebugCheck">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Отображает окно переводчика. Следует использовать только для разработки переводчиков.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Режим отладки</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="ignoreSslCheck">
<property name="text">
<string>Игнорировать ошибки SSL</string>
</property>
</widget>
</item>
<item row="1" column="1" colspan="2">
<widget class="QCheckBox" name="forceRotateCheck">
<property name="text">
<string>Принудительно менять переводчики</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<tabstops>
<tabstop>tabWidget</tabstop>
<tabstop>captureEdit</tabstop>
<tabstop>repeatCaptureEdit</tabstop>
<tabstop>repeatEdit</tabstop>
<tabstop>clipboardEdit</tabstop>
<tabstop>trayRadio</tabstop>
<tabstop>dialogRadio</tabstop>
<tabstop>proxyTypeCombo</tabstop>
<tabstop>proxyHostEdit</tabstop>
<tabstop>proxyPortSpin</tabstop>
<tabstop>proxyUserEdit</tabstop>
<tabstop>proxyPassEdit</tabstop>
<tabstop>proxySaveCheck</tabstop>
<tabstop>tessdataEdit</tabstop>
<tabstop>tessdataButton</tabstop>
<tabstop>ocrLangCombo</tabstop>
<tabstop>imageScaleSpin</tabstop>
<tabstop>recognizerFixTable</tabstop>
<tabstop>doTranslationCheck</tabstop>
<tabstop>translatorDebugCheck</tabstop>
<tabstop>translateTimeoutSpin</tabstop>
<tabstop>translateLangCombo</tabstop>
<tabstop>translatorList</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>SettingsEditor</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>256</x>
<y>447</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>SettingsEditor</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>324</x>
<y>447</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

15
StAssert.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef ST_ASSERT_H
#define ST_ASSERT_H
#include <assert.h>
#if !defined(ST_ASSERT)
# if defined(ST_NO_ASSERT)
# define ST_ASSERT(CONDITION)
# else
# define ST_ASSERT(CONDITION) assert (CONDITION)
# endif
#endif
#endif // ST_ASSERT_H

82
TranslatorHelper.cpp Normal file
View File

@ -0,0 +1,82 @@
#include <QSettings>
#include <QDir>
#include <QFile>
#include <QApplication>
#include "TranslatorHelper.h"
#include "Settings.h"
TranslatorHelper::TranslatorHelper ()
: translatorsDir_ ("translators"), currentIndex_ (0), triesLeft_ (0) {
translatorsDir_ = QApplication::applicationDirPath () + QDir::separator () + translatorsDir_;
}
void TranslatorHelper::setEnabledTranslators (const QStringList &enabled) const {
QSettings settings;
settings.beginGroup (settings_names::translationGroup);
settings.setValue (settings_names::translators, enabled.join ("|"));
}
QStringList TranslatorHelper::possibleTranslators (QStringList &enabled) const {
#define GET(FIELD) settings.value (settings_names::FIELD, settings_values::FIELD)
QSettings settings;
settings.beginGroup (settings_names::translationGroup);
QStringList exist = QDir (translatorsDir_).entryList (QStringList () << "*.js", QDir::Files);
QStringList saved = GET (translators).toString ().split ("|", QString::SkipEmptyParts);
QStringList on, off;
std::copy_if (saved.begin (), saved.end (), std::back_inserter (on), [&](const QString &i) {
return exist.contains (i);
});
on = on.isEmpty () ? exist : on;
std::copy_if (exist.begin (), exist.end (), std::back_inserter (off), [&](const QString &i) {
return !on.contains (i);
});
enabled = on;
return (on + off);
#undef GET
}
QStringList TranslatorHelper::enabledTranslatorScripts () const {
QStringList enabled;
possibleTranslators (enabled);
QStringList scripts;
foreach (const QString &name, enabled) {
QFile f (translatorsDir_ + QDir::separator () + name);
if (f.open (QFile::ReadOnly)) {
QString script = QString::fromUtf8 (f.readAll ());
if (!script.isEmpty ()) {
scripts << script;
}
}
}
return scripts;
}
void TranslatorHelper::loadScripts () {
scripts_ = enabledTranslatorScripts ();
}
void TranslatorHelper::newItem (bool forceRotate) {
triesLeft_ = scripts_.size ();
currentIndex_ = forceRotate ? currentIndex_ + 1 : 0;
}
QString TranslatorHelper::nextScript () {
--triesLeft_;
if (++currentIndex_ >= scripts_.size ()) {
currentIndex_ = 0;
}
return currentScript ();
}
QString TranslatorHelper::currentScript () const {
return (triesLeft_ > 0 ? scripts_.at (currentIndex_) : QString ());
}
bool TranslatorHelper::gotScripts () const {
return !scripts_.isEmpty ();
}

28
TranslatorHelper.h Normal file
View File

@ -0,0 +1,28 @@
#ifndef TRANSLATORHELPER_H
#define TRANSLATORHELPER_H
#include <QStringList>
class TranslatorHelper {
public:
TranslatorHelper ();
QStringList possibleTranslators (QStringList &enabled) const;
QStringList enabledTranslatorScripts () const;
void setEnabledTranslators (const QStringList &enabled) const;
void loadScripts ();
void newItem (bool forceRotate);
QString nextScript ();
QString currentScript () const;
bool gotScripts () const;
private:
QString translatorsDir_;
QStringList scripts_;
int currentIndex_;
int triesLeft_;
};
#endif // TRANSLATORHELPER_H

264
Updater.cpp Normal file
View File

@ -0,0 +1,264 @@
#include <QDir>
#include <QFile>
#include <QJsonDocument>
#include <QJsonArray>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QMessageBox>
#include <QApplication>
#include "Updater.h"
#include "StAssert.h"
namespace {
#define FIELD(NAME) const QString _ ## NAME = #NAME
FIELD (Application);
FIELD (name);
FIELD (version);
FIELD (compatibleVersion);
FIELD (built_in);
FIELD (versionString);
FIELD (permissions);
FIELD (url);
FIELD (path);
#undef FIELD
#if defined(Q_OS_WIN)
const QString _platform = "_win";
#elif defined(Q_OS_LINUX)
const QString _platform = "_linux";
#endif
QString versionField (const QJsonObject &component, const QString &field) {
return component.contains (field + _platform)
? component[field + _platform].toVariant ().toString ()
: component[field].toVariant ().toString ();
}
QFileInfo fileDir (const QString &fileName) {
return QFileInfo (fileName).absolutePath ();
}
}
Updater::Updater (QObject *parent)
: QObject (parent),
network_ (new QNetworkAccessManager (this)),
componentsUpdating_ (0) {
updatesFileName_ = QApplication::applicationDirPath () + QDir::separator () + "updates.json";
backupSuffix_ = "_backup";
connect (network_, SIGNAL (finished (QNetworkReply *)),
SLOT (replyFinished (QNetworkReply *)));
getCurrentVersion ();
updateCurrentVersion ();
}
QDateTime Updater::nextCheckTime (const QDateTime &lastCheckTime, int updateType) const {
QDateTime nextTime;
switch (updateType) {
case UpdateTypeDaily:
nextTime = lastCheckTime.addDays (1);
break;
case UpdateTypeWeekly:
nextTime = lastCheckTime.addDays (7);
break;
case UpdateTypeMonthly:
nextTime = lastCheckTime.addDays (30);
break;
case UpdateTypeNever:
default:
return QDateTime ();
}
if (nextTime < QDateTime::currentDateTime ()) {
return QDateTime::currentDateTime ().addSecs (5);
}
return nextTime;
}
void Updater::getCurrentVersion () {
QFile f (":/version.json");
if (f.open (QFile::ReadOnly)) {
currentVersion_ = QJsonDocument::fromJson (f.readAll ()).object ();
f.close ();
}
else {
emit error (tr ("Ошибка определения текущей версии. Обновление недоступно."));
}
}
void Updater::updateCurrentVersion () {
QFile f (updatesFileName_);
if (!f.open (QFile::ReadOnly)) {
return;
}
QJsonObject updated = QJsonDocument::fromJson (f.readAll ()).object ();
f.close ();
foreach (const QString &component, updated.keys ()) {
QJsonObject current = currentVersion_[component].toObject ();
int updatedVersion = updated[component].toInt ();
if (current[_built_in].toBool () || current[_version].toInt () >= updatedVersion) {
continue;
}
current[_version] = updatedVersion;
currentVersion_[component] = current;
}
}
QString Updater::currentAppVersion () const {
return currentVersion_[_Application].toObject ()[_versionString].toString ();
}
void Updater::checkForUpdates () {
getAvailableVersion ();
}
void Updater::getAvailableVersion () {
QNetworkRequest request (versionField (currentVersion_, _url));
request.setAttribute (QNetworkRequest::User, _version);
network_->get (request);
}
void Updater::replyFinished (QNetworkReply *reply) {
if (reply->error () != QNetworkReply::NoError) {
emit tr ("Ошибка загрузки информации для обновления.");
return;
}
QByteArray content = reply->readAll ();
QString component = reply->request ().attribute (QNetworkRequest::User).toString ();
if (component == _version) {
availableVersion_ = QJsonDocument::fromJson (content).object ();
parseAvailableVersion ();
}
else if (availableVersion_.contains (component) && !content.isEmpty ()) {
installComponent (component, content);
}
reply->deleteLater ();
}
void Updater::parseAvailableVersion () {
QStringList inaccessible, incompatible;
QStringList updateList;
QDir currentDir;
foreach (const QString &component, availableVersion_.keys ()) {
QJsonObject available = availableVersion_[component].toObject ();
QJsonObject current = currentVersion_[component].toObject ();
QString path = versionField (available, _path);
if (path.isEmpty ()) {
continue;
}
QFileInfo installDir = fileDir (path);
if (!installDir.exists ()) {
currentDir.mkpath (installDir.absoluteFilePath ());
}
if (!installDir.isWritable ()) { // check dir because install = remove + make new
inaccessible << installDir.absoluteFilePath ();
}
if (current[_version].toInt () < versionField (available, _compatibleVersion).toInt ()) {
incompatible << component;
}
if (!QFile::exists (path) || current[_version].toInt () < available[_version].toInt ()) {
updateList << component;
}
}
if (updateList.isEmpty ()) {
return;
}
QFileInfo updateFileDir = fileDir (updatesFileName_);
if (!updateFileDir.isWritable ()) {
inaccessible << updateFileDir.absoluteFilePath ();
}
inaccessible.removeDuplicates ();
QString message = tr ("Доступно обновлений: %1.\n").arg (updateList.size ());
QMessageBox::StandardButtons buttons = QMessageBox::Ok;
if (!incompatible.isEmpty ()) {
message += tr ("Несовместимых обновлений: %1.\nВыполните обновление вручную.")
.arg (incompatible.size ());
}
else if (!inaccessible.isEmpty ()) {
message += tr ("Недоступных для записи директорий: %1.\n%2\nИзмените права доступа и "
"повторите попытку или выполните обновление вручную.")
.arg (inaccessible.size ()).arg (inaccessible.join ("\n"));
}
else {
message += tr ("Обновить?");
buttons = QMessageBox::Yes | QMessageBox::No;
}
int result = QMessageBox::question (NULL, tr ("Обновление"), message, buttons);
if (result == QMessageBox::Yes) {
componentsUpdating_ = updateList.size ();
foreach (const QString &component, updateList) {
getComponent (component);
}
}
}
void Updater::getComponent (const QString &component) {
QJsonObject available = availableVersion_[component].toObject ();
QString path = versionField (available, _path);
if (path.isEmpty ()) {
--componentsUpdating_;
return;
}
QString url = versionField (available, _url);
if (url.isEmpty ()) { // just remove component
installComponent (component, QByteArray ());
}
else {
QNetworkRequest request (url);
request.setAttribute (QNetworkRequest::User, component);
network_->get (request);
}
}
void Updater::installComponent (const QString &component, const QByteArray &newContent) {
--componentsUpdating_;
ST_ASSERT (availableVersion_.contains (component));
QJsonObject available = availableVersion_[component].toObject ();
QString path = versionField (available, _path);
ST_ASSERT (!path.isEmpty ());
QString backup = path + backupSuffix_;
QFile::remove (backup);
QFile::rename (path, backup);
if (!newContent.isEmpty ()) {
QFile f (path);
if (!f.open (QFile::WriteOnly)) {
emit error (tr ("Ошибка обновления файла (%1).").arg (path));
return;
}
f.write (newContent);
f.close ();
bool ok;
QFileDevice::Permissions perm (available[_permissions].toString ().toUInt (&ok, 16));
if (ok) {
f.setPermissions (perm);
}
}
updateVersionInfo (component, available[_version].toInt ());
if (componentsUpdating_ == 0) {
emit updated ();
QString message = tr ("Обновление завершено. Для активации некоторых компонентов "
"может потребоваться перезапуск.");
QMessageBox::information (NULL, tr ("Обновление"), message, QMessageBox::Ok);
}
}
void Updater::updateVersionInfo (const QString &component, int version) {
QFile f (updatesFileName_);
if (!f.open (QFile::ReadWrite)) {
emit error (tr ("Ошибка обновления файла с текущей версией."));
return;
}
QJsonObject updated = QJsonDocument::fromJson (f.readAll ()).object ();
updated[component] = version;
f.seek (0);
f.write (QJsonDocument (updated).toJson ());
f.close ();
}

65
Updater.h Normal file
View File

@ -0,0 +1,65 @@
#ifndef UPDATER_H
#define UPDATER_H
#include <QObject>
#include <QJsonObject>
#include <QNetworkAccessManager>
/*!
* \brief The Updater class.
*
* Allows to download and copy files from remote source to local machine.
*/
class Updater : public QObject {
Q_OBJECT
public:
enum UpdateType {
UpdateTypeNever, UpdateTypeDaily, UpdateTypeWeekly, UpdateTypeMonthly
};
explicit Updater (QObject *parent = 0);
QString currentAppVersion () const;
//! Initiate updates check.
void checkForUpdates ();
//! Get nearest update check time based on given settings.
QDateTime nextCheckTime (const QDateTime &lastCheckTime, int updateType) const;
signals:
void error (const QString &message);
//! Emited after all components updated.
void updated ();
private slots:
//! Handle remote downloads finish.
void replyFinished (QNetworkReply *reply);
private:
//! Load current version info (built-in).
void getCurrentVersion ();
//! Update current version info with information about preformed updates.
void updateCurrentVersion ();
//! Load latest available version info from remote source.
void getAvailableVersion ();
//! Check is updates available, prompt user and start update.
void parseAvailableVersion ();
//! Start update of given component.
void getComponent (const QString &component);
//! Finalize update of given component with given new content.
void installComponent (const QString &component, const QByteArray &newContent);
//! Save information about component update on disk (for updateCurrentVersion()).
void updateVersionInfo (const QString &component, int version);
private:
QNetworkAccessManager *network_;
QJsonObject availableVersion_;
QJsonObject currentVersion_;
QString updatesFileName_;
int componentsUpdating_;
QString backupSuffix_;
};
#endif // UPDATER_H

21
Utils.cpp Normal file
View File

@ -0,0 +1,21 @@
#include <QNetworkProxy>
#include "Utils.h"
QString encode (const QString &source) {
if (source.isEmpty ()) {
return source;
}
char encKeys[] = {14, 26, 99, 43};
std::string result = source.toStdString ();
for (int i = 0, end = result.size (); i < end; ++i) {
result [i] = result[i] ^ encKeys[ i % sizeof(encKeys)];
}
return QString::fromUtf8 (result.data ());
}
QList<int> proxyTypeOrder () {
QList<int> proxyOrder;
proxyOrder << QNetworkProxy::NoProxy << QNetworkProxy::Socks5Proxy << QNetworkProxy::HttpProxy;
return proxyOrder;
}

10
Utils.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef UTILS_H
#define UTILS_H
#include <QString>
QString encode (const QString &source);
QList<int> proxyTypeOrder ();
#endif // UTILS_H

156
WebTranslator.cpp Normal file
View File

@ -0,0 +1,156 @@
#include <QWebView>
#include <QWebFrame>
#include <QSettings>
#include <QNetworkReply>
#include <QFile>
#include "WebTranslator.h"
#include "ProcessingItem.h"
#include "Settings.h"
#include "StAssert.h"
#include "WebTranslatorProxy.h"
#include "TranslatorHelper.h"
WebTranslator::WebTranslator ()
: QObject (),
proxy_ (new WebTranslatorProxy (this)), view_ (new QWebView),
translatorHelper_ (new TranslatorHelper), isReady_ (true),
ignoreSslErrors_ (settings_values::ignoreSslErrors),
forceRotateTranslators_ (settings_values::forceRotateTranslators) {
view_->settings ()->setAttribute (QWebSettings::AutoLoadImages, false);
view_->settings ()->setAttribute (QWebSettings::DeveloperExtrasEnabled, true);
view_->settings ()->setAttribute (QWebSettings::LocalStorageEnabled, true);
connect (view_, SIGNAL (loadFinished (bool)), SLOT (loadFinished (bool)));
connect (view_->page ()->mainFrame (), SIGNAL (javaScriptWindowObjectCleared ()),
this, SLOT (addProxyToView ()));
connect (view_->page ()->networkAccessManager (), SIGNAL (finished (QNetworkReply *)),
this, SLOT (replyFinished (QNetworkReply *)));
connect (view_->page ()->networkAccessManager (),
SIGNAL (sslErrors (QNetworkReply *, QList<QSslError>)),
this, SLOT (handleSslErrors (QNetworkReply *, QList<QSslError>)));
translationTimeout_.setSingleShot (true);
connect (&translationTimeout_, SIGNAL (timeout ()), SLOT (abortTranslation ()));
connect (proxy_, SIGNAL (translated (QString)), SLOT (proxyTranslated (QString)));
// Delay because it can emit signal that is not connected yet.
QTimer::singleShot (500, this, SLOT (applySettings ()));
}
WebTranslator::~WebTranslator () {
delete translatorHelper_;
delete view_;
}
void WebTranslator::addProxyToView () {
view_->page ()->mainFrame ()->addToJavaScriptWindowObject ("st_wtp", proxy_);
view_->page ()->mainFrame ()->evaluateJavaScript (translatorHelper_->currentScript ());
}
void WebTranslator::translate (ProcessingItem item) {
if (!item.isValid () || item.translateLanguage.isEmpty ()) {
emit translated (item);
return;
}
queue_.push_back (item);
translateQueued ();
}
void WebTranslator::translateQueued () {
if (isReady_ && !queue_.isEmpty ()) {
translatorHelper_->newItem (forceRotateTranslators_);
proxy_->setItem (queue_.first ());
if (!tryNextTranslator (true)) {
return;
}
}
}
void WebTranslator::proxyTranslated (const QString &text) {
if (!queue_.isEmpty () && queue_.first ().recognized == proxy_->sourceText ()) {
if (text.isEmpty () && tryNextTranslator ()) {
return;
}
ProcessingItem &item = queue_.first ();
item.translated = text;
emit translated (item);
}
finishTranslation (false);
}
void WebTranslator::handleSslErrors (QNetworkReply *reply, const QList<QSslError> &) {
if (ignoreSslErrors_) {
reply->ignoreSslErrors ();
}
}
void WebTranslator::abortTranslation () {
if (!tryNextTranslator ()) {
emit error (tr ("Перевод отменен по таймауту."));
finishTranslation ();
}
}
void WebTranslator::loadFinished (bool ok) {
if (!ok && !tryNextTranslator ()) {
QString url = view_->url ().toString ();
emit error (tr ("Ошибка загрузки страницы (%1) для перевода.").arg (url));
finishTranslation ();
}
}
void WebTranslator::finishTranslation (bool markAsTranslated) {
translationTimeout_.stop ();
view_->stop ();
if (!queue_.isEmpty ()) {
if (markAsTranslated) {
emit translated (queue_.first ());
}
queue_.pop_front ();
}
isReady_ = true;
translateQueued ();
}
bool WebTranslator::tryNextTranslator (bool firstTime) {
QString script = firstTime ? translatorHelper_->currentScript ()
: translatorHelper_->nextScript ();
if (script.isEmpty ()) {
return false;
}
translationTimeout_.stop ();
view_->stop ();
addProxyToView ();
view_->page ()->mainFrame ()->evaluateJavaScript ("translate();");
isReady_ = false;
translationTimeout_.start ();
return true;
}
void WebTranslator::replyFinished (QNetworkReply *reply) {
emit proxy_->resourceLoaded (reply->url ().toString ());
}
void WebTranslator::applySettings () {
QSettings settings;
settings.beginGroup (settings_names::translationGroup);
#define GET(NAME) settings.value (settings_names::NAME, settings_values::NAME)
translationTimeout_.setInterval (GET (translationTimeout).toInt () * 1000);
translatorHelper_->loadScripts ();
if (!translatorHelper_->gotScripts ()) {
emit error (tr ("Нет сценариев для перевода. Измените настройки."));
}
bool debugMode = GET (translationDebugMode).toBool ();
setDebugMode (debugMode);
ignoreSslErrors_ = GET (ignoreSslErrors).toBool ();
forceRotateTranslators_ = GET (forceRotateTranslators).toBool ();
#undef GET
}
void WebTranslator::setDebugMode (bool isOn) {
view_->setVisible (isOn);
}

57
WebTranslator.h Normal file
View File

@ -0,0 +1,57 @@
#ifndef WEBTRANSLATOR_H
#define WEBTRANSLATOR_H
#include <QObject>
#include <QMap>
#include <QTimer>
#include "ProcessingItem.h"
class QWebView;
class QNetworkReply;
class QSslError;
class WebTranslatorProxy;
class TranslatorHelper;
class WebTranslator : public QObject {
Q_OBJECT
public:
explicit WebTranslator ();
~WebTranslator ();
signals:
void translated (ProcessingItem item);
void error (QString text);
public slots:
void translate (ProcessingItem item);
void applySettings ();
void setDebugMode (bool isOn);
private slots:
void loadFinished (bool ok);
void replyFinished (QNetworkReply *reply);
void addProxyToView ();
void abortTranslation ();
void proxyTranslated (const QString &text);
void handleSslErrors (QNetworkReply *reply, const QList<QSslError> &errors);
private:
void translateQueued ();
void finishTranslation (bool markAsTranslated = true);
bool tryNextTranslator (bool firstTime = false);
private:
WebTranslatorProxy *proxy_;
QWebView *view_;
TranslatorHelper *translatorHelper_;
QVector<ProcessingItem> queue_;
bool isReady_;
bool ignoreSslErrors_;
bool forceRotateTranslators_;
QTimer translationTimeout_;
};
#endif // WEBTRANSLATOR_H

25
WebTranslatorProxy.cpp Normal file
View File

@ -0,0 +1,25 @@
#include "WebTranslatorProxy.h"
#include "ProcessingItem.h"
WebTranslatorProxy::WebTranslatorProxy (QObject *parent)
: QObject (parent) {
}
void WebTranslatorProxy::setItem (const ProcessingItem &item) {
sourceText_ = item.recognized;
sourceLanguage_ = item.ocrLanguage;
resultLanguage_ = item.translateLanguage;
}
const QString &WebTranslatorProxy::sourceText () const {
return sourceText_;
}
const QString &WebTranslatorProxy::sourceLanguage () const {
return sourceLanguage_;
}
const QString &WebTranslatorProxy::resultLanguage () const {
return resultLanguage_;
}

37
WebTranslatorProxy.h Normal file
View File

@ -0,0 +1,37 @@
#ifndef WEBTRANSLATORPROXY_H
#define WEBTRANSLATORPROXY_H
#include <QObject>
class ProcessingItem;
/*!
* \brief Proxy class between WebTranslator and QWebView.
*/
class WebTranslatorProxy : public QObject {
Q_OBJECT
Q_PROPERTY (QString sourceText READ sourceText)
Q_PROPERTY (QString sourceLanguage READ sourceLanguage)
Q_PROPERTY (QString resultLanguage READ resultLanguage)
public:
explicit WebTranslatorProxy (QObject *parent = 0);
void setItem (const ProcessingItem &item);
const QString &sourceText () const;
const QString &sourceLanguage () const;
const QString &resultLanguage () const;
signals:
void translated (const QString &text);
void resourceLoaded (const QString &url);
private:
QString sourceText_;
QString sourceLanguage_;
QString resultLanguage_;
};
#endif // WEBTRANSLATORPROXY_H

69
distr/Changelog_en.txt Normal file
View File

@ -0,0 +1,69 @@
Changes.
2.0.2:
* Added force translator rotation option.
2.0.1:
* Fixed installer.
2.0.0:
* Added a version for linux.
* Added support for multiple monitors.
* Added ability of recognition without translation.
* Added ability to recapture from old image.
* Added ability to recapture without closing capture window.
* Added ability to re-recognize other language.
* Added ability to display intermediate result when error occured.
* Added support for different translation services.
* Added ability to copy image to clipboard.
* Added ability to edit recognized text.
* Added ability to automatically correct common recognition mistakes.
* Added ability to use a proxy.
* Added ability to swap translation and recognition languages.
* Updated icons.
* Show progress on icon.
* Added ability to automatically update.
1.2.3:
* Fixed possible crash.
* Added version information and some error messages.
1.2.2:
* Added alternative translation source.
1.2.1:
* Fixed the bug with the lack of translation.
* Fixed the bug with the use of language recognition by default when you select another one in OCR region selection mode.
1.2.0:
+ Changed installer.
+ Added all available languages for recognition.
+ Added ability to specify language when selecting the field of recognition using right click.
+ Human readable language names.
* Reduced memory usage.
* Updated libraries.
1.1.3:
* Added library libgcc_s_dw2-1.dll.
* Updated libraries.
1.1.2:
* If you specify in the settings the path to tessdata characters "\" or "/" at the end of the path are no longer required.
1.1.1:
* Fixed an issue with incorrect window size when display results.
1.1.0:
+ Displays the result in the window, along with the picture.
+ Context menu expanded. Added buttons display the last result and copy it to the clipboard.

69
distr/Changelog_ru.txt Normal file
View File

@ -0,0 +1,69 @@
Изменения.
2.0.2:
* Добавлена настройка принудительной смены переводчиков.
2.0.1:
* Исправлен установщик.
2.0.0:
* Добавлена версия под linux.
* Добавлена поддержка нескольких мониторов.
* Добавлеа возможность распознание без перевода.
* Добавлена возможность вызова старого рисунка для выделения.
* Добавлена возможность повторного выделения без закрытия окна захвата.
* Добавлена возможность повторного распознания на другом языке.
* Добавлена возможность отображения промежуточного результата при ошибке перевода.
* Добавлена поддержка разных сервисов перевода.
* Добавлена возможность копирования изображения в буфер.
* Добавлена возможность редакции распознанного текста.
* Добавлена возможность автоматической коррекции частых ошибок распознавания.
* Добавлена возможность использования прокси.
* Добавлена возможность разовой смена языка перевода и распознавания.
* Обновлены иконки.
* Добавлено отображение статуса работы на иконке.
* Добавлена возможность автоматического обновления.
1.2.3:
* Устранена возможная причина падения.
* Добавлена информация о версии и некоторые сообщения об ошибках.
1.2.2:
* Добавлен альтернативный источник перевода.
1.2.1:
* Устранена ошибка отсутствия перевода.
* Устранена ошибка использования языка распознавания по умолчанию при выборе другого в окне выделения области распознавания.
1.2.0:
+ Изменен установщик.
+ В установщик добавлены все доступные языки для распознавания.
+ Добавлена возможность указания языка при выборе области распознавания при помощи выделения с правым кликом.
+ Человекочитаемые названия языков.
* Уменьшено потребление памяти.
* Обновлены библиотеки.
1.1.3:
- В установщик добавлена библиотека libgcc_s_dw2-1.dll.
- Обновлены библиотеки.
1.1.2:
- При задании в настройках пути к tessdata символы «\» или «/» в конце пути теперь не обязательны.
1.1.1:
- Пофиксен баг с неверным размером окна отображения результатов.
1.1.0:
- Отображение результата в окошке, вместе с картинкой.
- Контекстное меню расширено. Добавлены кнопки отображения последнего результата и копирования его в буфер обмена.

16
distr/deb/DEBIAN/control Normal file
View File

@ -0,0 +1,16 @@
Package: screen-translator
Version: 1
Section: graphics
Architecture: amd64
Depends: libtesseract3, libqt5webkit5, libqt5x11extras5
Recommends: tesseract-ocr-eng, tesseract-ocr-rus, tesseract-ocr-deu, tesseract-ocr-spa, tesseract-ocr-chi-sim, tesseract-ocr-fra, tesseract-ocr-jpn
Installed-Size: 1
Priority: optional
Maintainer: Gres <translator@gres.biz>
Homepage: https://github.com/OneMoreGres/ScreenTranslator
Description: Screen capture, OCR and translation tool.
This software allows to translate any text on screen.
Basically it is a combination of screen capture,
OCR and translation tools.

View File

@ -0,0 +1,9 @@
[Desktop Entry]
Version=1
Name=Screen Translator
Comment=Screen capture, OCR and translation tool.
Exec=/opt/ScreenTranslator/ScreenTranslator
Icon=ScreenTranslator.png
Terminal=false
Type=Application
Categories=Graphics;

129
distr/iss/InnoSetup.iss Normal file
View File

@ -0,0 +1,129 @@
; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
#ifexist "defines.iss"
#include "defines.iss"
#endif
#ifndef MyAppVersion
#define MyAppVersion "1.0.0"
#endif
#define MyAppName "Screen Translator"
#define MyAppPublisher "Gres"
#define MyAppURL "http://gres.biz/screen-translator/"
#define MyAppExeName "ScreenTranslator.exe"
#define MyAppDescription "Screen capture and translation tool"
[Setup]
; NOTE: The value of AppId uniquely identifies this application.
; Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{016F399E-0EED-476C-AB00-8AD0FF5BFD77}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
;AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName={pf}\{#MyAppName}
DefaultGroupName={#MyAppName}
AllowNoIcons=yes
PrivilegesRequired=admin
CloseApplications=yes
OutputDir=..
OutputBaseFilename=screen-translator-online-{#MyAppVersion}
SetupIconFile=icon.ico
RestartIfNeededByRun=False
ShowLanguageDialog=auto
VersionInfoCompany={#MyAppPublisher}
VersionInfoDescription={#MyAppDescription}
VersionInfoProductName={#MyAppName}
VersionInfoProductVersion={#MyAppVersion}
VersionInfoVersion={#MyAppVersion}
Compression=lzma2/ultra64
InternalCompressLevel=ultra
SolidCompression=yes
[Languages]
Name: "en"; MessagesFile: "compiler:Default.isl,default.isl"; LicenseFile: "LICENSE_en.md"; InfoBeforeFile: "Changelog_en.txt"
Name: "ru"; MessagesFile: "compiler:Languages\Russian.isl,russian.isl"; LicenseFile: "LICENSE_ru.md"; InfoBeforeFile: "Changelog_ru.txt"
[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
Name: "startupicon"; Description: "{cm:CreateStartupIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked; OnlyBelowVersion: 0,6.1
[Icons]
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}"
Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: quicklaunchicon
Name: "{commonstartup}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: startupicon
[Run]
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
Filename: "{tmp}\vcredist_x86.exe"; Description: "{cm:InstallRedist}"; Parameters: "/install"; Flags: postinstall skipifsilent
[Files]
Source: "content\ScreenTranslator.exe"; DestDir: "{app}"; Flags: ignoreversion; Components: Executable
Source: "content\*.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: Libraries
Source: "content\platforms\*"; DestDir: "{app}\platforms"; Flags: ignoreversion; Components: Libraries
Source: "content\translators\*"; DestDir: "{app}\translators"; Flags: ignoreversion; Components: Translators
Source: "content\vcredist_x86.exe"; DestDir: "{tmp}"; Flags: deleteafterinstall;
[Types]
Name: "custom"; Description: "Custom installation"; Flags: iscustom
[Components]
Name: "Executable"; Description: "{cm:Executables}"; Types: custom; Flags: fixed;
Name: "Libraries"; Description: "{cm:Libraries}"; Types: custom; Flags: fixed;
Name: "Translators"; Description: "{cm:Translators}"; Types: custom; Flags: fixed;
#include "tessdata.iss"
[UninstallDelete]
Type: files; Name: "{app}\updates.json"
Type: files; Name: "{app}\st_subs.csv"
[UninstallRun]
Filename: "taskkill.exe"; Parameters: "/IM ScreenTranslator.exe /T /F"
[Code]
#define DwinsHs_Use_Predefined_Downloading_WizardPage
#define DwinsHs_Auto_Continue
#include "dwinshs.iss"
procedure InitializeWizard();
begin
DwinsHs_InitializeWizard(wpPreparing);
end;
procedure CurPageChanged(CurPageID: Integer);
begin
DwinsHs_CurPageChanged(CurPageID, nil, nil);
end;
function ShouldSkipPage(CurPageId: Integer): Boolean;
begin
Result := False;
DwinsHs_ShouldSkipPage(CurPageId, Result);
end;
function BackButtonClick(CurPageID: Integer): Boolean;
begin
Result := True;
DwinsHs_BackButtonClick(CurPageID);
end;
function NextButtonClick(CurPageID: Integer): Boolean;
begin
Result := True;
DwinsHs_NextButtonClick(CurPageID, Result);
end;
procedure CancelButtonClick(CurPageID: Integer; var Cancel, Confirm: Boolean);
begin
DwinsHs_CancelButtonClick(CurPageID, Cancel, Confirm);
end;

View File

@ -0,0 +1,91 @@
; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
#ifexist "defines.iss"
#include "defines.iss"
#endif
#ifndef MyAppVersion
#define MyAppVersion "1.0.0"
#endif
#define MyAppName "Screen Translator"
#define MyAppPublisher "Gres"
#define MyAppURL "http://gres.biz/screen-translator/"
#define MyAppExeName "ScreenTranslator.exe"
#define MyAppDescription "Screen capture and translation tool"
[Setup]
; NOTE: The value of AppId uniquely identifies this application.
; Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{016F399E-0EED-476C-AB00-8AD0FF5BFD77}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
;AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName={pf}\{#MyAppName}
DefaultGroupName={#MyAppName}
AllowNoIcons=yes
PrivilegesRequired=admin
CloseApplications=yes
OutputDir=..
OutputBaseFilename=screen-translator-offline-{#MyAppVersion}
SetupIconFile=icon.ico
RestartIfNeededByRun=False
ShowLanguageDialog=auto
VersionInfoCompany={#MyAppPublisher}
VersionInfoDescription={#MyAppDescription}
VersionInfoProductName={#MyAppName}
VersionInfoProductVersion={#MyAppVersion}
VersionInfoVersion={#MyAppVersion}
Compression=lzma2/ultra64
InternalCompressLevel=ultra
SolidCompression=yes
[Languages]
Name: "en"; MessagesFile: "compiler:Default.isl,default.isl"; LicenseFile: "LICENSE_en.md"; InfoBeforeFile: "Changelog_en.txt"
Name: "ru"; MessagesFile: "compiler:Languages\Russian.isl,russian.isl"; LicenseFile: "LICENSE_ru.md"; InfoBeforeFile: "Changelog_ru.txt"
[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
Name: "startupicon"; Description: "{cm:CreateStartupIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked; OnlyBelowVersion: 0,6.1
[Icons]
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}"
Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: quicklaunchicon
Name: "{commonstartup}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: startupicon
[Run]
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
Filename: "{tmp}\vcredist_x86.exe"; Description: "{cm:InstallRedist}"; Parameters: "/install"; Flags: postinstall skipifsilent
[Files]
Source: "content\ScreenTranslator.exe"; DestDir: "{app}"; Flags: ignoreversion; Components: Executable
Source: "content\*.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: Libraries
Source: "content\platforms\*"; DestDir: "{app}\platforms"; Flags: ignoreversion; Components: Libraries
Source: "content\translators\*"; DestDir: "{app}\translators"; Flags: ignoreversion; Components: Translators
Source: "content\vcredist_x86.exe"; DestDir: "{tmp}"; Flags: deleteafterinstall;
[Types]
Name: "custom"; Description: "Custom installation"; Flags: iscustom
[Components]
Name: "Executable"; Description: "{cm:Executables}"; Types: custom; Flags: fixed;
Name: "Libraries"; Description: "{cm:Libraries}"; Types: custom; Flags: fixed;
Name: "Translators"; Description: "{cm:Translators}"; Types: custom; Flags: fixed;
#include "tessdataBuiltin.iss"
[UninstallDelete]
Type: files; Name: "{app}\updates.json"
Type: files; Name: "{app}\st_subs.csv"
[UninstallRun]
Filename: "taskkill.exe"; Parameters: "/IM ScreenTranslator.exe /T /F"

9
distr/iss/LICENSE_ru.md Normal file
View File

@ -0,0 +1,9 @@
Лицензия MIT
Copyright (c) 2017 Gres (gres@gres.biz)
Данная лицензия разрешает лицам, получившим копию данного программного обеспечения и сопутствующей документации (в дальнейшем именуемыми «Программное Обеспечение»), безвозмездно использовать Программное Обеспечение без ограничений, включая неограниченное право на использование, копирование, изменение, добавление, публикацию, распространение, сублицензирование и/или продажу копий Программного Обеспечения, а также лицам, которым предоставляется данное Программное Обеспечение, при соблюдении следующих условий:
Указанное выше уведомление об авторском праве и данные условия должны быть включены во все копии или значимые части данного Программного Обеспечения.
ДАННОЕ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ ПРЕДОСТАВЛЯЕТСЯ «КАК ЕСТЬ», БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ, ЯВНО ВЫРАЖЕННЫХ ИЛИ ПОДРАЗУМЕВАЕМЫХ, ВКЛЮЧАЯ ГАРАНТИИ ТОВАРНОЙ ПРИГОДНОСТИ, СООТВЕТСТВИЯ ПО ЕГО КОНКРЕТНОМУ НАЗНАЧЕНИЮ И ОТСУТСТВИЯ НАРУШЕНИЙ, НО НЕ ОГРАНИЧИВАЯСЬ ИМИ. НИ В КАКОМ СЛУЧАЕ АВТОРЫ ИЛИ ПРАВООБЛАДАТЕЛИ НЕ НЕСУТ ОТВЕТСТВЕННОСТИ ПО КАКИМ-ЛИБО ИСКАМ, ЗА УЩЕРБ ИЛИ ПО ИНЫМ ТРЕБОВАНИЯМ, В ТОМ ЧИСЛЕ, ПРИ ДЕЙСТВИИ КОНТРАКТА, ДЕЛИКТЕ ИЛИ ИНОЙ СИТУАЦИИ, ВОЗНИКШИМ ИЗ-ЗА ИСПОЛЬЗОВАНИЯ ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ ИЛИ ИНЫХ ДЕЙСТВИЙ С ПРОГРАММНЫМ ОБЕСПЕЧЕНИЕМ.

109
distr/iss/code2langTr.txt Normal file
View File

@ -0,0 +1,109 @@
#iso-639-3 standard code to names
afr Afrikaans Африкаанс
amh Amharic Амхарский
ara Arabic Арабский
asm Assamese Ассамский
aze Azerbaijani Азербайджанский
#aze_cyrl aze_cyrl
bel Belarusian Белорусский
ben Bengali Бенгальский
bod Tibetan Тибетский
bos Bosnian Боснийский
bul Bulgarian Болгарии
cat Catalan Каталонский
ceb Cebuano Кебуано
ces Czech Чешский
chi_sim Chineese_simplified Китайский_упрощенный
chi_tra Chineese_traditional Китайский_традиционный
chr Cherokee Чероки
cym Welsh Валлийский
dan Danish Датский
#dan_frak dan_frak
deu German Немецкий
#deu_frak deu_frak
dzo Dzongkha Джонгкха
ell Modern_Greek Новогреческий
eng English Английский
enm Middle_English Средневековый_английский
epo Esperanto Эсперанто
equ Math Математика
est Estonian Эстонский
eus Basque Басков
fas Persian Персидский
fin Finnish Финский
fra French Французский
frk Frankish Франкский
frm Middle_French Средневековый_французский
gle Irish Ирландский
glg Galician Галисийский
grc Ancient_Greek Древнегреческий
guj Gujarati Гуджарати
hat Haitian Гаити
heb Hebrew Иврит
hin Hindi Хинди
hrv Croatian Хорватский
hun Hungarian Венгерский
iku Inuktitut Инуктитут
ind Indonesian Индонезийский
isl Icelandic Исландский
ita Italian Итальянский
#ita_old ita_old
jav Javanese Яванский
jpn Japanese Японский
kan Kannada Каннада
kat Georgian Грузинский
#kat_old kat_old
kaz Kazakh Казахский
khm Khmer Кхмерский
kir Kirghiz Киргизский
kor Korean Корейский
kur Kurdish Курдский
lao Lao Лао
lat Latin Латинский
lav Latvian Латышский
lit Lithuanian Литовский
mal Malayalam Малаялам
mar Marathi Маратхи
mkd Macedonian Македонский
mlt Maltese Мальтийский
msa Malay Малайский
mya Burmese Бирманский
nep Nepali Непальский
nld Dutch Голландский
nor Norwegian Норвежский
ori Oriya Ория
#osd OSD OSD
pan Panjabi Панджаби
pol Polish Польский
por Portuguese Португальский
pus Pushto Пушту
ron Romanian Румынский
rus Russian Русский
san Sanskrit Санскрит
sin Sinhala Сингальский
slk Slovak Словацкий
#slk_frak slk_frak
slv Slovenian Словенский
spa Spanish Испанский
#spa_old spa_old
sqi Albanian Албанский
srp Serbian Сербский
#srp_latn srp_latn
swa Swahili Суахили
swe Swedish Шведский
syr Syriac Сирийский
tam Tamil Тамил
tel Telugu Телугу
tgk Tajik Таджикиский
tgl Tagalog Тагальский
tha Thai Тайский
tir Tigrinya Тиграи
tur Turkish Турецкий
uig Uighur Уйгурский
ukr Ukrainian Украинский
urd Urdu Урду
uzb Uzbek Узбекский
#uzb_cyrl uzb_cyrl
vie Vietnamese Вьетнамский
yid Yiddish Идиш

106
distr/iss/default.isl Normal file
View File

@ -0,0 +1,106 @@
[CustomMessages]
CreateStartupIcon=Create autostart icon
Executables=Executables
Libraries=Libraries
Translators=Translators
InstallRedist=Install VC redistributable
Languages=OCR Languages
Afrikaans=Afrikaans
Albanian=Albanian
Amharic=Amharic
Ancient_Greek=Ancient Greek
Arabic=Arabic
Assamese=Assamese
Azerbaijani=Azerbaijani
Basque=Basque
Belarusian=Belarusian
Bengali=Bengali
Bosnian=Bosnian
Bulgarian=Bulgarian
Burmese=Burmese
Catalan=Catalan
Cebuano=Cebuano
Cherokee=Cherokee
Chineese_simplified=Chineese simplified
Chineese_traditional=Chineese traditional
Croatian=Croatian
Czech=Czech
Danish=Danish
Dutch=Dutch
Dzongkha=Dzongkha
English=English
Esperanto=Esperanto
Estonian=Estonian
Finnish=Finnish
Frankish=Frankish
French=French
Galician=Galician
Georgian=Georgian
German=German
Gujarati=Gujarati
Haitian=Haitian
Hebrew=Hebrew
Hindi=Hindi
Hungarian=Hungarian
Icelandic=Icelandic
Indonesian=Indonesian
Inuktitut=Inuktitut
Irish=Irish
Italian=Italian
Japanese=Japanese
Javanese=Javanese
Kannada=Kannada
Kazakh=Kazakh
Khmer=Khmer
Kirghiz=Kirghiz
Korean=Korean
Kurdish=Kurdish
Lao=Lao
Latin=Latin
Latvian=Latvian
Lithuanian=Lithuanian
Macedonian=Macedonian
Malay=Malay
Malayalam=Malayalam
Maltese=Maltese
Marathi=Marathi
Math=Math
Middle_English=Middle English
Middle_French=Middle French
Modern_Greek=Modern Greek
Nepali=Nepali
Norwegian=Norwegian
Oriya=Oriya
Panjabi=Panjabi
Persian=Persian
Polish=Polish
Portuguese=Portuguese
Pushto=Pushto
Romanian=Romanian
Russian=Russian
Sanskrit=Sanskrit
Serbian=Serbian
Sinhala=Sinhala
Slovak=Slovak
Slovenian=Slovenian
Spanish=Spanish
Swahili=Swahili
Swedish=Swedish
Syriac=Syriac
Tagalog=Tagalog
Tajik=Tajik
Tamil=Tamil
Telugu=Telugu
Thai=Thai
Tibetan=Tibetan
Tigrinya=Tigrinya
Turkish=Turkish
Uighur=Uighur
Ukrainian=Ukrainian
Urdu=Urdu
Uzbek=Uzbek
Vietnamese=Vietnamese
Welsh=Welsh
Yiddish=Yiddish

1266
distr/iss/dwinshs.iss Normal file

File diff suppressed because it is too large Load Diff

94
distr/iss/make_tess_iss.sh Executable file
View File

@ -0,0 +1,94 @@
#!/bin/bash
TESSDATA_DIR="$1"
if [ -z "$TESSDATA_DIR" ]; then echo "Usage $0 <tessdata_dir>"; exit 0; fi
TESSDATA_DIR=`readlink -e $TESSDATA_DIR`
OUT_FILE="tessdata.iss"
OUT_FILE=`readlink -m $OUT_FILE`
LANGS_FILE="code2langTr.txt"
function getLangsOrder {
local FIELD=$1
local ORDER=`cat $LANGS_FILE | cut -d' ' -f$FIELD | sort`
local FNAMES=""
for i in $ORDER; do
local FNAME=`grep "$i" $LANGS_FILE | cut -d' ' -f1`
if [[ -z "$FNAME" || "${FNAME:0:1}" == "#" ]]; then
continue;
fi
FNAMES=$FNAMES" $FNAME"
done
echo $FNAMES
}
FILES="[Files]\n"
COMPONENTS="[Components]\nName: \"Languages\"; Description: \"{cm:Languages}\"; Types: custom\n"
MESSAGES_EN="\n[CustomMessages]\nen.Languages=OCR Languages\n"
MESSAGES_RU="\n[CustomMessages]\nru.Languages=Языки распознавания\n"
PREV_LANG=""
CUSTOM_LANGS="eng"
function fillIss {
local LANG_FIELD=$1
local COMPONENT_LANG=$2
local ONLY_COMPONENTS=$3
COMPONENTS=$COMPONENTS"\n"
local ORDER=`cat $LANGS_FILE | cut -d' ' -f$LANG_FIELD | sort`
for i in $ORDER; do
local LANG_LINE=$(grep " $i " $LANGS_FILE)
local FNAME=$(echo "$LANG_LINE" | cut -d' ' -f1)
local LANG_EN=$(echo "$LANG_LINE" | cut -d' ' -f2)
local LANG_RU=$(echo "$LANG_LINE" | cut -d' ' -f3)
if [[ -z "$FNAME" || "${FNAME:0:1}" == "#" ]]; then
continue;
fi
local CUR_LANG_FILES=`find $TESSDATA_DIR -name "$FNAME.*"`
if [ -z "$CUR_LANG_FILES" ]; then
echo "no lang"
continue
fi
local COMPONENT_SIZE=0
for s in `find $TESSDATA_DIR -name "$FNAME.*" -exec wc -c {} \; | cut -d' ' -f1`; do
COMPONENT_SIZE=$(expr $COMPONENT_SIZE + $s)
done
TYPES=""
if [[ $CUSTOM_LANGS =~ $FNAME ]]; then
TYPES="custom"
fi
if [ ! -z "$TYPES" ]; then
TYPES="Types: $TYPES; ";
fi
COMPONENTS=$COMPONENTS"Name: \"Languages\\\\$LANG_EN\"; Description: \"{cm:$LANG_EN}\"; Languages: $COMPONENT_LANG;
$TYPES ExtraDiskSpaceRequired: $COMPONENT_SIZE\n"
if $ONLY_COMPONENTS; then
continue;
fi
MESSAGES_EN=$MESSAGES_EN"en.$LANG_EN=$(echo "$LANG_EN" | sed 's/_/ /g')\n"
MESSAGES_RU=$MESSAGES_RU"ru.$LANG_EN=$(echo "$LANG_RU" | sed 's/_/ /g')\n"
for f in $CUR_LANG_FILES; do
local FNAME=$(basename "$f")
FILES=$FILES"Source: \"{tmp}\\\\$FNAME\"; DestDir: \"{app}\\\\tessdata\"; Components: Languages\\\\$LANG_EN;
Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\\\\$FNAME'),
'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/$FNAME', 'ST_setup', 'Get', 0);\n"
done
done
}
fillIss 2 "en" false
fillIss 3 "ru" true
echo -e $FILES > $OUT_FILE
echo -e $COMPONENTS >> $OUT_FILE
echo -e $MESSAGES_EN >> $OUT_FILE
echo -e $MESSAGES_RU >> $OUT_FILE
iconv -f utf8 -t cp1251 $OUT_FILE -o $OUT_FILE.1
mv $OUT_FILE.1 $OUT_FILE

122
distr/iss/russian.isl Normal file
View File

@ -0,0 +1,122 @@
[CustomMessages]
CreateStartupIcon=Äîáàâèòü â àâòîçàïóñê
Executables=Èñïîëíÿåìûå ôàéëû
Libraries=Áèáëèîòåêè
Translators=Ïåðåâîä÷èêè
InstallRedist=Óñòàíîâèòü áèáëèîòåêè Visual C++
DwinsHs_PageCaption =Çàãðóçêà ôàéëîâ
DwinsHs_PageDescription =Ïîæàëóéñòà, äîæäèòåñü îêîí÷àíèÿ çàãðóçêè...
DwinsHs_TotalProgress =Îáùèé ïðîãðåññ:
DwinsHs_CurrentFile =Òåêóùèé ôàéë:
DwinsHs_File =Ôàéë:
DwinsHs_Speed =Ñêîðîñòü:
DwinsHs_Status =Ñòàòóñ:
DwinsHs_ElapsedTime =Çàòðà÷åííîå âðåìÿ:
DwinsHs_RemainingTime =Îñòàâøååñÿ âðåìÿ:
DwinsHs_Status_GetFileInformation =Ïîëó÷åíèå ðàçìåðà ôàéëà
DwinsHs_Status_StartingDownload =Íà÷àëî çàãðóçêè
DwinsHs_Status_Downloading =Çàãðóçêà
DwinsHs_Status_DownlaodComplete =Çàãðóçêà çàâåðøåíà
Languages=ßçûêè ðàñïîçíàâàíèÿ
Afrikaans=Àôðèêààíñ
Albanian=Àëáàíñêèé
Amharic=Àìõàðñêèé
Ancient_Greek=Äðåâíåãðå÷åñêèé
Arabic=Àðàáñêèé
Assamese=Àññàìñêèé
Azerbaijani=Àçåðáàéäæàíñêèé
Basque=Áàñêîâ
Belarusian=Áåëîðóññêèé
Bengali=Áåíãàëüñêèé
Bosnian=Áîñíèéñêèé
Bulgarian=Áîëãàðèè
Burmese=Áèðìàíñêèé
Catalan=Êàòàëîíñêèé
Cebuano=Êåáóàíî
Cherokee=×åðîêè
Chineese_simplified=Êèòàéñêèé óïðîùåííûé
Chineese_traditional=Êèòàéñêèé òðàäèöèîííûé
Croatian=Õîðâàòñêèé
Czech=×åøñêèé
Danish=Äàòñêèé
Dutch=Ãîëëàíäñêèé
Dzongkha=Äæîíãêõà
English=Àíãëèéñêèé
Esperanto=Ýñïåðàíòî
Estonian=Ýñòîíñêèé
Finnish=Ôèíñêèé
Frankish=Ôðàíêñêèé
French=Ôðàíöóçñêèé
Galician=Ãàëèñèéñêèé
Georgian=Ãðóçèíñêèé
German=Íåìåöêèé
Gujarati=Ãóäæàðàòè
Haitian=Ãàèòè
Hebrew=Èâðèò
Hindi=Õèíäè
Hungarian=Âåíãåðñêèé
Icelandic=Èñëàíäñêèé
Indonesian=Èíäîíåçèéñêèé
Inuktitut=Èíóêòèòóò
Irish=Èðëàíäñêèé
Italian=Èòàëüÿíñêèé
Japanese=ßïîíñêèé
Javanese=ßâàíñêèé
Kannada=Êàííàäà
Kazakh=Êàçàõñêèé
Khmer=Êõìåðñêèé
Kirghiz=Êèðãèçñêèé
Korean=Êîðåéñêèé
Kurdish=Êóðäñêèé
Lao=Ëàî
Latin=Ëàòèíñêèé
Latvian=Ëàòûøñêèé
Lithuanian=Ëèòîâñêèé
Macedonian=Ìàêåäîíñêèé
Malay=Ìàëàéñêèé
Malayalam=Ìàëàÿëàì
Maltese=Ìàëüòèéñêèé
Marathi=Ìàðàòõè
Math=Ìàòåìàòèêà
Middle_English=Ñðåäíåâåêîâûé àíãëèéñêèé
Middle_French=Ñðåäíåâåêîâûé ôðàíöóçñêèé
Modern_Greek=Íîâîãðå÷åñêèé
Nepali=Íåïàëüñêèé
Norwegian=Íîðâåæñêèé
Oriya=Îðèÿ
Panjabi=Ïàíäæàáè
Persian=Ïåðñèäñêèé
Polish=Ïîëüñêèé
Portuguese=Ïîðòóãàëüñêèé
Pushto=Ïóøòó
Romanian=Ðóìûíñêèé
Russian=Ðóññêèé
Sanskrit=Ñàíñêðèò
Serbian=Ñåðáñêèé
Sinhala=Ñèíãàëüñêèé
Slovak=Ñëîâàöêèé
Slovenian=Ñëîâåíñêèé
Spanish=Èñïàíñêèé
Swahili=Ñóàõèëè
Swedish=Øâåäñêèé
Syriac=Ñèðèéñêèé
Tagalog=Òàãàëüñêèé
Tajik=Òàäæèêèñêèé
Tamil=Òàìèë
Telugu=Òåëóãó
Thai=Òàéñêèé
Tibetan=Òèáåòñêèé
Tigrinya=Òèãðàè
Turkish=Òóðåöêèé
Uighur=Óéãóðñêèé
Ukrainian=Óêðàèíñêèé
Urdu=Óðäó
Uzbek=Óçáåêñêèé
Vietnamese=Âüåòíàìñêèé
Welsh=Âàëëèéñêèé
Yiddish=Èäèø

348
distr/iss/tessdata.iss Normal file
View File

@ -0,0 +1,348 @@
[Files]
Source: "{tmp}\afr.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Afrikaans; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\afr.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/afr.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\sqi.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Albanian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\sqi.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/sqi.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\amh.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Amharic; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\amh.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/amh.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\grc.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Ancient_Greek; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\grc.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/grc.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\ara.cube.nn"; DestDir: "{app}\tessdata"; Components: Languages\Arabic; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ara.cube.nn'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/ara.cube.nn', 'ST_setup', 'Get', 0);
Source: "{tmp}\ara.cube.bigrams"; DestDir: "{app}\tessdata"; Components: Languages\Arabic; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ara.cube.bigrams'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/ara.cube.bigrams', 'ST_setup', 'Get', 0);
Source: "{tmp}\ara.cube.word-freq"; DestDir: "{app}\tessdata"; Components: Languages\Arabic; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ara.cube.word-freq'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/ara.cube.word-freq', 'ST_setup', 'Get', 0);
Source: "{tmp}\ara.cube.size"; DestDir: "{app}\tessdata"; Components: Languages\Arabic; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ara.cube.size'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/ara.cube.size', 'ST_setup', 'Get', 0);
Source: "{tmp}\ara.cube.params"; DestDir: "{app}\tessdata"; Components: Languages\Arabic; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ara.cube.params'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/ara.cube.params', 'ST_setup', 'Get', 0);
Source: "{tmp}\ara.cube.fold"; DestDir: "{app}\tessdata"; Components: Languages\Arabic; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ara.cube.fold'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/ara.cube.fold', 'ST_setup', 'Get', 0);
Source: "{tmp}\ara.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Arabic; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ara.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/ara.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\ara.cube.lm"; DestDir: "{app}\tessdata"; Components: Languages\Arabic; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ara.cube.lm'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/ara.cube.lm', 'ST_setup', 'Get', 0);
Source: "{tmp}\asm.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Assamese; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\asm.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/asm.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\aze.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Azerbaijani; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\aze.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/aze.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\eus.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Basque; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\eus.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/eus.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\bel.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Belarusian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\bel.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/bel.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\ben.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Bengali; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ben.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/ben.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\bos.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Bosnian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\bos.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/bos.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\bul.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Bulgarian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\bul.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/bul.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\mya.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Burmese; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\mya.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/mya.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\cat.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Catalan; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\cat.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/cat.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\ceb.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Cebuano; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ceb.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/ceb.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\chr.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Cherokee; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\chr.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/chr.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\chi_sim.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Chineese_simplified; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\chi_sim.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/chi_sim.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\chi_tra.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Chineese_traditional; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\chi_tra.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/chi_tra.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\hrv.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Croatian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\hrv.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/hrv.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\ces.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Czech; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ces.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/ces.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\dan.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Danish; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\dan.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/dan.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\nld.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Dutch; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\nld.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/nld.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\dzo.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Dzongkha; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\dzo.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/dzo.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\eng.cube.word-freq"; DestDir: "{app}\tessdata"; Components: Languages\English; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\eng.cube.word-freq'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/eng.cube.word-freq', 'ST_setup', 'Get', 0);
Source: "{tmp}\eng.cube.params"; DestDir: "{app}\tessdata"; Components: Languages\English; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\eng.cube.params'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/eng.cube.params', 'ST_setup', 'Get', 0);
Source: "{tmp}\eng.cube.bigrams"; DestDir: "{app}\tessdata"; Components: Languages\English; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\eng.cube.bigrams'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/eng.cube.bigrams', 'ST_setup', 'Get', 0);
Source: "{tmp}\eng.cube.nn"; DestDir: "{app}\tessdata"; Components: Languages\English; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\eng.cube.nn'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/eng.cube.nn', 'ST_setup', 'Get', 0);
Source: "{tmp}\eng.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\English; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\eng.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/eng.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\eng.cube.fold"; DestDir: "{app}\tessdata"; Components: Languages\English; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\eng.cube.fold'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/eng.cube.fold', 'ST_setup', 'Get', 0);
Source: "{tmp}\eng.cube.size"; DestDir: "{app}\tessdata"; Components: Languages\English; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\eng.cube.size'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/eng.cube.size', 'ST_setup', 'Get', 0);
Source: "{tmp}\eng.tesseract_cube.nn"; DestDir: "{app}\tessdata"; Components: Languages\English; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\eng.tesseract_cube.nn'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/eng.tesseract_cube.nn', 'ST_setup', 'Get', 0);
Source: "{tmp}\eng.cube.lm"; DestDir: "{app}\tessdata"; Components: Languages\English; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\eng.cube.lm'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/eng.cube.lm', 'ST_setup', 'Get', 0);
Source: "{tmp}\epo.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Esperanto; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\epo.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/epo.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\est.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Estonian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\est.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/est.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\fin.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Finnish; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\fin.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/fin.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\frk.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Frankish; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\frk.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/frk.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\fra.tesseract_cube.nn"; DestDir: "{app}\tessdata"; Components: Languages\French; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\fra.tesseract_cube.nn'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/fra.tesseract_cube.nn', 'ST_setup', 'Get', 0);
Source: "{tmp}\fra.cube.params"; DestDir: "{app}\tessdata"; Components: Languages\French; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\fra.cube.params'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/fra.cube.params', 'ST_setup', 'Get', 0);
Source: "{tmp}\fra.cube.lm"; DestDir: "{app}\tessdata"; Components: Languages\French; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\fra.cube.lm'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/fra.cube.lm', 'ST_setup', 'Get', 0);
Source: "{tmp}\fra.cube.fold"; DestDir: "{app}\tessdata"; Components: Languages\French; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\fra.cube.fold'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/fra.cube.fold', 'ST_setup', 'Get', 0);
Source: "{tmp}\fra.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\French; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\fra.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/fra.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\fra.cube.size"; DestDir: "{app}\tessdata"; Components: Languages\French; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\fra.cube.size'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/fra.cube.size', 'ST_setup', 'Get', 0);
Source: "{tmp}\fra.cube.bigrams"; DestDir: "{app}\tessdata"; Components: Languages\French; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\fra.cube.bigrams'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/fra.cube.bigrams', 'ST_setup', 'Get', 0);
Source: "{tmp}\fra.cube.nn"; DestDir: "{app}\tessdata"; Components: Languages\French; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\fra.cube.nn'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/fra.cube.nn', 'ST_setup', 'Get', 0);
Source: "{tmp}\fra.cube.word-freq"; DestDir: "{app}\tessdata"; Components: Languages\French; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\fra.cube.word-freq'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/fra.cube.word-freq', 'ST_setup', 'Get', 0);
Source: "{tmp}\glg.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Galician; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\glg.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/glg.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\kat.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Georgian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\kat.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/kat.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\deu.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\German; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\deu.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/deu.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\guj.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Gujarati; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\guj.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/guj.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\hat.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Haitian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\hat.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/hat.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\heb.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Hebrew; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\heb.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/heb.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\hin.cube.nn"; DestDir: "{app}\tessdata"; Components: Languages\Hindi; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\hin.cube.nn'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/hin.cube.nn', 'ST_setup', 'Get', 0);
Source: "{tmp}\hin.cube.lm"; DestDir: "{app}\tessdata"; Components: Languages\Hindi; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\hin.cube.lm'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/hin.cube.lm', 'ST_setup', 'Get', 0);
Source: "{tmp}\hin.tesseract_cube.nn"; DestDir: "{app}\tessdata"; Components: Languages\Hindi; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\hin.tesseract_cube.nn'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/hin.tesseract_cube.nn', 'ST_setup', 'Get', 0);
Source: "{tmp}\hin.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Hindi; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\hin.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/hin.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\hin.cube.params"; DestDir: "{app}\tessdata"; Components: Languages\Hindi; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\hin.cube.params'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/hin.cube.params', 'ST_setup', 'Get', 0);
Source: "{tmp}\hin.cube.word-freq"; DestDir: "{app}\tessdata"; Components: Languages\Hindi; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\hin.cube.word-freq'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/hin.cube.word-freq', 'ST_setup', 'Get', 0);
Source: "{tmp}\hin.cube.fold"; DestDir: "{app}\tessdata"; Components: Languages\Hindi; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\hin.cube.fold'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/hin.cube.fold', 'ST_setup', 'Get', 0);
Source: "{tmp}\hin.cube.bigrams"; DestDir: "{app}\tessdata"; Components: Languages\Hindi; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\hin.cube.bigrams'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/hin.cube.bigrams', 'ST_setup', 'Get', 0);
Source: "{tmp}\hun.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Hungarian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\hun.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/hun.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\isl.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Icelandic; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\isl.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/isl.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\ind.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Indonesian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ind.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/ind.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\iku.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Inuktitut; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\iku.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/iku.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\gle.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Irish; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\gle.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/gle.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\ita.tesseract_cube.nn"; DestDir: "{app}\tessdata"; Components: Languages\Italian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ita.tesseract_cube.nn'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/ita.tesseract_cube.nn', 'ST_setup', 'Get', 0);
Source: "{tmp}\ita.cube.word-freq"; DestDir: "{app}\tessdata"; Components: Languages\Italian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ita.cube.word-freq'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/ita.cube.word-freq', 'ST_setup', 'Get', 0);
Source: "{tmp}\ita.cube.params"; DestDir: "{app}\tessdata"; Components: Languages\Italian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ita.cube.params'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/ita.cube.params', 'ST_setup', 'Get', 0);
Source: "{tmp}\ita.cube.fold"; DestDir: "{app}\tessdata"; Components: Languages\Italian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ita.cube.fold'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/ita.cube.fold', 'ST_setup', 'Get', 0);
Source: "{tmp}\ita.cube.bigrams"; DestDir: "{app}\tessdata"; Components: Languages\Italian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ita.cube.bigrams'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/ita.cube.bigrams', 'ST_setup', 'Get', 0);
Source: "{tmp}\ita.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Italian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ita.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/ita.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\ita.cube.size"; DestDir: "{app}\tessdata"; Components: Languages\Italian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ita.cube.size'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/ita.cube.size', 'ST_setup', 'Get', 0);
Source: "{tmp}\ita.cube.nn"; DestDir: "{app}\tessdata"; Components: Languages\Italian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ita.cube.nn'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/ita.cube.nn', 'ST_setup', 'Get', 0);
Source: "{tmp}\ita.cube.lm"; DestDir: "{app}\tessdata"; Components: Languages\Italian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ita.cube.lm'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/ita.cube.lm', 'ST_setup', 'Get', 0);
Source: "{tmp}\jpn.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Japanese; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\jpn.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/jpn.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\jav.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Javanese; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\jav.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/jav.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\kan.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Kannada; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\kan.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/kan.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\kaz.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Kazakh; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\kaz.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/kaz.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\khm.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Khmer; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\khm.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/khm.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\kir.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Kirghiz; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\kir.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/kir.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\kor.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Korean; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\kor.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/kor.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\kur.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Kurdish; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\kur.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/kur.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\lao.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Lao; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\lao.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/lao.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\lat.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Latin; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\lat.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/lat.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\lav.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Latvian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\lav.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/lav.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\lit.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Lithuanian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\lit.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/lit.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\mkd.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Macedonian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\mkd.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/mkd.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\msa.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Malay; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\msa.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/msa.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\mal.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Malayalam; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\mal.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/mal.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\mlt.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Maltese; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\mlt.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/mlt.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\mar.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Marathi; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\mar.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/mar.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\equ.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Math; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\equ.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/equ.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\enm.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Middle_English; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\enm.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/enm.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\frm.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Middle_French; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\frm.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/frm.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\ell.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Modern_Greek; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ell.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/ell.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\nep.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Nepali; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\nep.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/nep.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\nor.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Norwegian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\nor.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/nor.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\ori.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Oriya; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ori.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/ori.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\pan.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Panjabi; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\pan.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/pan.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\fas.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Persian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\fas.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/fas.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\pol.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Polish; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\pol.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/pol.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\por.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Portuguese; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\por.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/por.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\pus.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Pushto; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\pus.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/pus.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\ron.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Romanian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ron.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/ron.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\rus.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Russian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\rus.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/rus.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\rus.cube.size"; DestDir: "{app}\tessdata"; Components: Languages\Russian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\rus.cube.size'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/rus.cube.size', 'ST_setup', 'Get', 0);
Source: "{tmp}\rus.cube.fold"; DestDir: "{app}\tessdata"; Components: Languages\Russian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\rus.cube.fold'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/rus.cube.fold', 'ST_setup', 'Get', 0);
Source: "{tmp}\rus.cube.lm"; DestDir: "{app}\tessdata"; Components: Languages\Russian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\rus.cube.lm'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/rus.cube.lm', 'ST_setup', 'Get', 0);
Source: "{tmp}\rus.cube.word-freq"; DestDir: "{app}\tessdata"; Components: Languages\Russian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\rus.cube.word-freq'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/rus.cube.word-freq', 'ST_setup', 'Get', 0);
Source: "{tmp}\rus.cube.nn"; DestDir: "{app}\tessdata"; Components: Languages\Russian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\rus.cube.nn'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/rus.cube.nn', 'ST_setup', 'Get', 0);
Source: "{tmp}\rus.cube.params"; DestDir: "{app}\tessdata"; Components: Languages\Russian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\rus.cube.params'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/rus.cube.params', 'ST_setup', 'Get', 0);
Source: "{tmp}\san.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Sanskrit; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\san.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/san.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\srp.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Serbian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\srp.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/srp.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\sin.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Sinhala; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\sin.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/sin.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\slk.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Slovak; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\slk.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/slk.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\slv.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Slovenian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\slv.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/slv.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\spa.cube.word-freq"; DestDir: "{app}\tessdata"; Components: Languages\Spanish; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\spa.cube.word-freq'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/spa.cube.word-freq', 'ST_setup', 'Get', 0);
Source: "{tmp}\spa.cube.lm"; DestDir: "{app}\tessdata"; Components: Languages\Spanish; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\spa.cube.lm'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/spa.cube.lm', 'ST_setup', 'Get', 0);
Source: "{tmp}\spa.cube.fold"; DestDir: "{app}\tessdata"; Components: Languages\Spanish; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\spa.cube.fold'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/spa.cube.fold', 'ST_setup', 'Get', 0);
Source: "{tmp}\spa.cube.size"; DestDir: "{app}\tessdata"; Components: Languages\Spanish; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\spa.cube.size'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/spa.cube.size', 'ST_setup', 'Get', 0);
Source: "{tmp}\spa.cube.bigrams"; DestDir: "{app}\tessdata"; Components: Languages\Spanish; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\spa.cube.bigrams'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/spa.cube.bigrams', 'ST_setup', 'Get', 0);
Source: "{tmp}\spa.cube.nn"; DestDir: "{app}\tessdata"; Components: Languages\Spanish; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\spa.cube.nn'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/spa.cube.nn', 'ST_setup', 'Get', 0);
Source: "{tmp}\spa.cube.params"; DestDir: "{app}\tessdata"; Components: Languages\Spanish; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\spa.cube.params'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/spa.cube.params', 'ST_setup', 'Get', 0);
Source: "{tmp}\spa.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Spanish; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\spa.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/spa.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\swa.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Swahili; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\swa.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/swa.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\swe.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Swedish; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\swe.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/swe.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\syr.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Syriac; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\syr.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/syr.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\tgl.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Tagalog; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\tgl.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/tgl.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\tgk.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Tajik; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\tgk.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/tgk.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\tam.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Tamil; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\tam.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/tam.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\tel.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Telugu; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\tel.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/tel.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\tha.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Thai; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\tha.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/tha.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\bod.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Tibetan; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\bod.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/bod.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\tir.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Tigrinya; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\tir.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/tir.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\tur.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Turkish; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\tur.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/tur.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\uig.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Uighur; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\uig.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/uig.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\ukr.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Ukrainian; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\ukr.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/ukr.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\urd.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Urdu; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\urd.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/urd.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\uzb.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Uzbek; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\uzb.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/uzb.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\vie.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Vietnamese; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\vie.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/vie.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\cym.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Welsh; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\cym.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/cym.traineddata', 'ST_setup', 'Get', 0);
Source: "{tmp}\yid.traineddata"; DestDir: "{app}\tessdata"; Components: Languages\Yiddish; Flags: external; Check: DwinsHs_Check(ExpandConstant('{tmp}\yid.traineddata'), 'https://github.com/tesseract-ocr/tessdata/raw/3.04.00/yid.traineddata', 'ST_setup', 'Get', 0);
[Components]
Name: "Languages"; Description: "{cm:Languages}"; Types: custom
Name: "Languages\Afrikaans"; Description: "{cm:Afrikaans}"; Languages: en; ExtraDiskSpaceRequired: 5198548
Name: "Languages\Albanian"; Description: "{cm:Albanian}"; Languages: en; ExtraDiskSpaceRequired: 6587325
Name: "Languages\Amharic"; Description: "{cm:Amharic}"; Languages: en; ExtraDiskSpaceRequired: 2953500
Name: "Languages\Ancient_Greek"; Description: "{cm:Ancient_Greek}"; Languages: en; ExtraDiskSpaceRequired: 5182527
Name: "Languages\Arabic"; Description: "{cm:Arabic}"; Languages: en; ExtraDiskSpaceRequired: 28534834
Name: "Languages\Assamese"; Description: "{cm:Assamese}"; Languages: en; ExtraDiskSpaceRequired: 15827072
Name: "Languages\Azerbaijani"; Description: "{cm:Azerbaijani}"; Languages: en; ExtraDiskSpaceRequired: 6615244
Name: "Languages\Basque"; Description: "{cm:Basque}"; Languages: en; ExtraDiskSpaceRequired: 4969647
Name: "Languages\Belarusian"; Description: "{cm:Belarusian}"; Languages: en; ExtraDiskSpaceRequired: 6822594
Name: "Languages\Bengali"; Description: "{cm:Bengali}"; Languages: en; ExtraDiskSpaceRequired: 15552533
Name: "Languages\Bosnian"; Description: "{cm:Bosnian}"; Languages: en; ExtraDiskSpaceRequired: 5432328
Name: "Languages\Bulgarian"; Description: "{cm:Bulgarian}"; Languages: en; ExtraDiskSpaceRequired: 6026234
Name: "Languages\Burmese"; Description: "{cm:Burmese}"; Languages: en; ExtraDiskSpaceRequired: 69770179
Name: "Languages\Catalan"; Description: "{cm:Catalan}"; Languages: en; ExtraDiskSpaceRequired: 5356190
Name: "Languages\Cebuano"; Description: "{cm:Cebuano}"; Languages: en; ExtraDiskSpaceRequired: 1686752
Name: "Languages\Cherokee"; Description: "{cm:Cherokee}"; Languages: en; ExtraDiskSpaceRequired: 1083194
Name: "Languages\Chineese_simplified"; Description: "{cm:Chineese_simplified}"; Languages: en; ExtraDiskSpaceRequired: 42089623
Name: "Languages\Chineese_traditional"; Description: "{cm:Chineese_traditional}"; Languages: en; ExtraDiskSpaceRequired: 56692327
Name: "Languages\Croatian"; Description: "{cm:Croatian}"; Languages: en; ExtraDiskSpaceRequired: 9135966
Name: "Languages\Czech"; Description: "{cm:Czech}"; Languages: en; ExtraDiskSpaceRequired: 11896327
Name: "Languages\Danish"; Description: "{cm:Danish}"; Languages: en; ExtraDiskSpaceRequired: 7340575
Name: "Languages\Dutch"; Description: "{cm:Dutch}"; Languages: en; ExtraDiskSpaceRequired: 17098919
Name: "Languages\Dzongkha"; Description: "{cm:Dzongkha}"; Languages: en; ExtraDiskSpaceRequired: 3310882
Name: "Languages\English"; Description: "{cm:English}"; Languages: en; Types: custom; ExtraDiskSpaceRequired: 38371506
Name: "Languages\Esperanto"; Description: "{cm:Esperanto}"; Languages: en; ExtraDiskSpaceRequired: 6602178
Name: "Languages\Estonian"; Description: "{cm:Estonian}"; Languages: en; ExtraDiskSpaceRequired: 9644486
Name: "Languages\Finnish"; Description: "{cm:Finnish}"; Languages: en; ExtraDiskSpaceRequired: 13274908
Name: "Languages\Frankish"; Description: "{cm:Frankish}"; Languages: en; ExtraDiskSpaceRequired: 16451109
Name: "Languages\French"; Description: "{cm:French}"; Languages: en; ExtraDiskSpaceRequired: 37350210
Name: "Languages\Galician"; Description: "{cm:Galician}"; Languages: en; ExtraDiskSpaceRequired: 5520499
Name: "Languages\Georgian"; Description: "{cm:Georgian}"; Languages: en; ExtraDiskSpaceRequired: 6219735
Name: "Languages\German"; Description: "{cm:German}"; Languages: en; ExtraDiskSpaceRequired: 13367187
Name: "Languages\Gujarati"; Description: "{cm:Gujarati}"; Languages: en; ExtraDiskSpaceRequired: 10622356
Name: "Languages\Haitian"; Description: "{cm:Haitian}"; Languages: en; ExtraDiskSpaceRequired: 1349947
Name: "Languages\Hebrew"; Description: "{cm:Hebrew}"; Languages: en; ExtraDiskSpaceRequired: 4339016
Name: "Languages\Hindi"; Description: "{cm:Hindi}"; Languages: en; ExtraDiskSpaceRequired: 22717250
Name: "Languages\Hungarian"; Description: "{cm:Hungarian}"; Languages: en; ExtraDiskSpaceRequired: 12213770
Name: "Languages\Icelandic"; Description: "{cm:Icelandic}"; Languages: en; ExtraDiskSpaceRequired: 6098683
Name: "Languages\Indonesian"; Description: "{cm:Indonesian}"; Languages: en; ExtraDiskSpaceRequired: 6503178
Name: "Languages\Inuktitut"; Description: "{cm:Inuktitut}"; Languages: en; ExtraDiskSpaceRequired: 995246
Name: "Languages\Irish"; Description: "{cm:Irish}"; Languages: en; ExtraDiskSpaceRequired: 3482557
Name: "Languages\Italian"; Description: "{cm:Italian}"; Languages: en; ExtraDiskSpaceRequired: 32720949
Name: "Languages\Japanese"; Description: "{cm:Japanese}"; Languages: en; ExtraDiskSpaceRequired: 33072615
Name: "Languages\Javanese"; Description: "{cm:Javanese}"; Languages: en; ExtraDiskSpaceRequired: 4404351
Name: "Languages\Kannada"; Description: "{cm:Kannada}"; Languages: en; ExtraDiskSpaceRequired: 35657050
Name: "Languages\Kazakh"; Description: "{cm:Kazakh}"; Languages: en; ExtraDiskSpaceRequired: 4529022
Name: "Languages\Khmer"; Description: "{cm:Khmer}"; Languages: en; ExtraDiskSpaceRequired: 48851416
Name: "Languages\Kirghiz"; Description: "{cm:Kirghiz}"; Languages: en; ExtraDiskSpaceRequired: 5502225
Name: "Languages\Korean"; Description: "{cm:Korean}"; Languages: en; ExtraDiskSpaceRequired: 13309831
Name: "Languages\Kurdish"; Description: "{cm:Kurdish}"; Languages: en; ExtraDiskSpaceRequired: 2020502
Name: "Languages\Lao"; Description: "{cm:Lao}"; Languages: en; ExtraDiskSpaceRequired: 21118927
Name: "Languages\Latin"; Description: "{cm:Latin}"; Languages: en; ExtraDiskSpaceRequired: 6028030
Name: "Languages\Latvian"; Description: "{cm:Latvian}"; Languages: en; ExtraDiskSpaceRequired: 7802105
Name: "Languages\Lithuanian"; Description: "{cm:Lithuanian}"; Languages: en; ExtraDiskSpaceRequired: 8916163
Name: "Languages\Macedonian"; Description: "{cm:Macedonian}"; Languages: en; ExtraDiskSpaceRequired: 3837583
Name: "Languages\Malay"; Description: "{cm:Malay}"; Languages: en; ExtraDiskSpaceRequired: 6495742
Name: "Languages\Malayalam"; Description: "{cm:Malayalam}"; Languages: en; ExtraDiskSpaceRequired: 8786470
Name: "Languages\Maltese"; Description: "{cm:Maltese}"; Languages: en; ExtraDiskSpaceRequired: 5118233
Name: "Languages\Marathi"; Description: "{cm:Marathi}"; Languages: en; ExtraDiskSpaceRequired: 14237379
Name: "Languages\Math"; Description: "{cm:Math}"; Languages: en; ExtraDiskSpaceRequired: 2251826
Name: "Languages\Middle_English"; Description: "{cm:Middle_English}"; Languages: en; ExtraDiskSpaceRequired: 2105888
Name: "Languages\Middle_French"; Description: "{cm:Middle_French}"; Languages: en; ExtraDiskSpaceRequired: 15831815
Name: "Languages\Modern_Greek"; Description: "{cm:Modern_Greek}"; Languages: en; ExtraDiskSpaceRequired: 5422512
Name: "Languages\Nepali"; Description: "{cm:Nepali}"; Languages: en; ExtraDiskSpaceRequired: 15862542
Name: "Languages\Norwegian"; Description: "{cm:Norwegian}"; Languages: en; ExtraDiskSpaceRequired: 8262167
Name: "Languages\Oriya"; Description: "{cm:Oriya}"; Languages: en; ExtraDiskSpaceRequired: 7900659
Name: "Languages\Panjabi"; Description: "{cm:Panjabi}"; Languages: en; ExtraDiskSpaceRequired: 10212006
Name: "Languages\Persian"; Description: "{cm:Persian}"; Languages: en; ExtraDiskSpaceRequired: 4803733
Name: "Languages\Polish"; Description: "{cm:Polish}"; Languages: en; ExtraDiskSpaceRequired: 13918058
Name: "Languages\Portuguese"; Description: "{cm:Portuguese}"; Languages: en; ExtraDiskSpaceRequired: 12914622
Name: "Languages\Pushto"; Description: "{cm:Pushto}"; Languages: en; ExtraDiskSpaceRequired: 2493826
Name: "Languages\Romanian"; Description: "{cm:Romanian}"; Languages: en; ExtraDiskSpaceRequired: 7957608
Name: "Languages\Russian"; Description: "{cm:Russian}"; Languages: en; ExtraDiskSpaceRequired: 39371802
Name: "Languages\Sanskrit"; Description: "{cm:Sanskrit}"; Languages: en; ExtraDiskSpaceRequired: 22747749
Name: "Languages\Serbian"; Description: "{cm:Serbian}"; Languages: en; ExtraDiskSpaceRequired: 4611681
Name: "Languages\Sinhala"; Description: "{cm:Sinhala}"; Languages: en; ExtraDiskSpaceRequired: 6793740
Name: "Languages\Slovak"; Description: "{cm:Slovak}"; Languages: en; ExtraDiskSpaceRequired: 9126966
Name: "Languages\Slovenian"; Description: "{cm:Slovenian}"; Languages: en; ExtraDiskSpaceRequired: 6824064
Name: "Languages\Spanish"; Description: "{cm:Spanish}"; Languages: en; ExtraDiskSpaceRequired: 39171233
Name: "Languages\Swahili"; Description: "{cm:Swahili}"; Languages: en; ExtraDiskSpaceRequired: 3861506
Name: "Languages\Swedish"; Description: "{cm:Swedish}"; Languages: en; ExtraDiskSpaceRequired: 9460295
Name: "Languages\Syriac"; Description: "{cm:Syriac}"; Languages: en; ExtraDiskSpaceRequired: 2734020
Name: "Languages\Tagalog"; Description: "{cm:Tagalog}"; Languages: en; ExtraDiskSpaceRequired: 4114554
Name: "Languages\Tajik"; Description: "{cm:Tajik}"; Languages: en; ExtraDiskSpaceRequired: 1119022
Name: "Languages\Tamil"; Description: "{cm:Tamil}"; Languages: en; ExtraDiskSpaceRequired: 5118600
Name: "Languages\Telugu"; Description: "{cm:Telugu}"; Languages: en; ExtraDiskSpaceRequired: 39318860
Name: "Languages\Thai"; Description: "{cm:Thai}"; Languages: en; ExtraDiskSpaceRequired: 13565168
Name: "Languages\Tibetan"; Description: "{cm:Tibetan}"; Languages: en; ExtraDiskSpaceRequired: 25231676
Name: "Languages\Tigrinya"; Description: "{cm:Tigrinya}"; Languages: en; ExtraDiskSpaceRequired: 1806235
Name: "Languages\Turkish"; Description: "{cm:Turkish}"; Languages: en; ExtraDiskSpaceRequired: 14069931
Name: "Languages\Uighur"; Description: "{cm:Uighur}"; Languages: en; ExtraDiskSpaceRequired: 2017575
Name: "Languages\Ukrainian"; Description: "{cm:Ukrainian}"; Languages: en; ExtraDiskSpaceRequired: 8043189
Name: "Languages\Urdu"; Description: "{cm:Urdu}"; Languages: en; ExtraDiskSpaceRequired: 4825658
Name: "Languages\Uzbek"; Description: "{cm:Uzbek}"; Languages: en; ExtraDiskSpaceRequired: 4286554
Name: "Languages\Vietnamese"; Description: "{cm:Vietnamese}"; Languages: en; ExtraDiskSpaceRequired: 6096118
Name: "Languages\Welsh"; Description: "{cm:Welsh}"; Languages: en; ExtraDiskSpaceRequired: 3789352
Name: "Languages\Yiddish"; Description: "{cm:Yiddish}"; Languages: en; ExtraDiskSpaceRequired: 4238718
Name: "Languages\Azerbaijani"; Description: "{cm:Azerbaijani}"; Languages: ru; ExtraDiskSpaceRequired: 6615244
Name: "Languages\Albanian"; Description: "{cm:Albanian}"; Languages: ru; ExtraDiskSpaceRequired: 6587325
Name: "Languages\Amharic"; Description: "{cm:Amharic}"; Languages: ru; ExtraDiskSpaceRequired: 2953500
Name: "Languages\English"; Description: "{cm:English}"; Languages: ru; Types: custom; ExtraDiskSpaceRequired: 38371506
Name: "Languages\Arabic"; Description: "{cm:Arabic}"; Languages: ru; ExtraDiskSpaceRequired: 28534834
Name: "Languages\Assamese"; Description: "{cm:Assamese}"; Languages: ru; ExtraDiskSpaceRequired: 15827072
Name: "Languages\Afrikaans"; Description: "{cm:Afrikaans}"; Languages: ru; ExtraDiskSpaceRequired: 5198548
Name: "Languages\Basque"; Description: "{cm:Basque}"; Languages: ru; ExtraDiskSpaceRequired: 4969647
Name: "Languages\Belarusian"; Description: "{cm:Belarusian}"; Languages: ru; ExtraDiskSpaceRequired: 6822594
Name: "Languages\Bengali"; Description: "{cm:Bengali}"; Languages: ru; ExtraDiskSpaceRequired: 15552533
Name: "Languages\Burmese"; Description: "{cm:Burmese}"; Languages: ru; ExtraDiskSpaceRequired: 69770179
Name: "Languages\Bulgarian"; Description: "{cm:Bulgarian}"; Languages: ru; ExtraDiskSpaceRequired: 6026234
Name: "Languages\Bosnian"; Description: "{cm:Bosnian}"; Languages: ru; ExtraDiskSpaceRequired: 5432328
Name: "Languages\Welsh"; Description: "{cm:Welsh}"; Languages: ru; ExtraDiskSpaceRequired: 3789352
Name: "Languages\Hungarian"; Description: "{cm:Hungarian}"; Languages: ru; ExtraDiskSpaceRequired: 12213770
Name: "Languages\Vietnamese"; Description: "{cm:Vietnamese}"; Languages: ru; ExtraDiskSpaceRequired: 6096118
Name: "Languages\Haitian"; Description: "{cm:Haitian}"; Languages: ru; ExtraDiskSpaceRequired: 1349947
Name: "Languages\Galician"; Description: "{cm:Galician}"; Languages: ru; ExtraDiskSpaceRequired: 5520499
Name: "Languages\Dutch"; Description: "{cm:Dutch}"; Languages: ru; ExtraDiskSpaceRequired: 17098919
Name: "Languages\Georgian"; Description: "{cm:Georgian}"; Languages: ru; ExtraDiskSpaceRequired: 6219735
Name: "Languages\Gujarati"; Description: "{cm:Gujarati}"; Languages: ru; ExtraDiskSpaceRequired: 10622356
Name: "Languages\Danish"; Description: "{cm:Danish}"; Languages: ru; ExtraDiskSpaceRequired: 7340575
Name: "Languages\Dzongkha"; Description: "{cm:Dzongkha}"; Languages: ru; ExtraDiskSpaceRequired: 3310882
Name: "Languages\Ancient_Greek"; Description: "{cm:Ancient_Greek}"; Languages: ru; ExtraDiskSpaceRequired: 5182527
Name: "Languages\Hebrew"; Description: "{cm:Hebrew}"; Languages: ru; ExtraDiskSpaceRequired: 4339016
Name: "Languages\Yiddish"; Description: "{cm:Yiddish}"; Languages: ru; ExtraDiskSpaceRequired: 4238718
Name: "Languages\Indonesian"; Description: "{cm:Indonesian}"; Languages: ru; ExtraDiskSpaceRequired: 6503178
Name: "Languages\Inuktitut"; Description: "{cm:Inuktitut}"; Languages: ru; ExtraDiskSpaceRequired: 995246
Name: "Languages\Irish"; Description: "{cm:Irish}"; Languages: ru; ExtraDiskSpaceRequired: 3482557
Name: "Languages\Icelandic"; Description: "{cm:Icelandic}"; Languages: ru; ExtraDiskSpaceRequired: 6098683
Name: "Languages\Spanish"; Description: "{cm:Spanish}"; Languages: ru; ExtraDiskSpaceRequired: 39171233
Name: "Languages\Italian"; Description: "{cm:Italian}"; Languages: ru; ExtraDiskSpaceRequired: 32720949
Name: "Languages\Kazakh"; Description: "{cm:Kazakh}"; Languages: ru; ExtraDiskSpaceRequired: 4529022
Name: "Languages\Kannada"; Description: "{cm:Kannada}"; Languages: ru; ExtraDiskSpaceRequired: 35657050
Name: "Languages\Catalan"; Description: "{cm:Catalan}"; Languages: ru; ExtraDiskSpaceRequired: 5356190
Name: "Languages\Cebuano"; Description: "{cm:Cebuano}"; Languages: ru; ExtraDiskSpaceRequired: 1686752
Name: "Languages\Kirghiz"; Description: "{cm:Kirghiz}"; Languages: ru; ExtraDiskSpaceRequired: 5502225
Name: "Languages\Chineese_traditional"; Description: "{cm:Chineese_traditional}"; Languages: ru; ExtraDiskSpaceRequired: 56692327
Name: "Languages\Chineese_simplified"; Description: "{cm:Chineese_simplified}"; Languages: ru; ExtraDiskSpaceRequired: 42089623
Name: "Languages\Korean"; Description: "{cm:Korean}"; Languages: ru; ExtraDiskSpaceRequired: 13309831
Name: "Languages\Kurdish"; Description: "{cm:Kurdish}"; Languages: ru; ExtraDiskSpaceRequired: 2020502
Name: "Languages\Khmer"; Description: "{cm:Khmer}"; Languages: ru; ExtraDiskSpaceRequired: 48851416
Name: "Languages\Lao"; Description: "{cm:Lao}"; Languages: ru; ExtraDiskSpaceRequired: 21118927
Name: "Languages\Latin"; Description: "{cm:Latin}"; Languages: ru; ExtraDiskSpaceRequired: 6028030
Name: "Languages\Latvian"; Description: "{cm:Latvian}"; Languages: ru; ExtraDiskSpaceRequired: 7802105
Name: "Languages\Lithuanian"; Description: "{cm:Lithuanian}"; Languages: ru; ExtraDiskSpaceRequired: 8916163
Name: "Languages\Macedonian"; Description: "{cm:Macedonian}"; Languages: ru; ExtraDiskSpaceRequired: 3837583
Name: "Languages\Malay"; Description: "{cm:Malay}"; Languages: ru; ExtraDiskSpaceRequired: 6495742
Name: "Languages\Malayalam"; Description: "{cm:Malayalam}"; Languages: ru; ExtraDiskSpaceRequired: 8786470
Name: "Languages\Maltese"; Description: "{cm:Maltese}"; Languages: ru; ExtraDiskSpaceRequired: 5118233
Name: "Languages\Marathi"; Description: "{cm:Marathi}"; Languages: ru; ExtraDiskSpaceRequired: 14237379
Name: "Languages\Math"; Description: "{cm:Math}"; Languages: ru; ExtraDiskSpaceRequired: 2251826
Name: "Languages\German"; Description: "{cm:German}"; Languages: ru; ExtraDiskSpaceRequired: 13367187
Name: "Languages\Nepali"; Description: "{cm:Nepali}"; Languages: ru; ExtraDiskSpaceRequired: 15862542
Name: "Languages\Modern_Greek"; Description: "{cm:Modern_Greek}"; Languages: ru; ExtraDiskSpaceRequired: 5422512
Name: "Languages\Norwegian"; Description: "{cm:Norwegian}"; Languages: ru; ExtraDiskSpaceRequired: 8262167
Name: "Languages\Oriya"; Description: "{cm:Oriya}"; Languages: ru; ExtraDiskSpaceRequired: 7900659
Name: "Languages\Panjabi"; Description: "{cm:Panjabi}"; Languages: ru; ExtraDiskSpaceRequired: 10212006
Name: "Languages\Persian"; Description: "{cm:Persian}"; Languages: ru; ExtraDiskSpaceRequired: 4803733
Name: "Languages\Polish"; Description: "{cm:Polish}"; Languages: ru; ExtraDiskSpaceRequired: 13918058
Name: "Languages\Portuguese"; Description: "{cm:Portuguese}"; Languages: ru; ExtraDiskSpaceRequired: 12914622
Name: "Languages\Pushto"; Description: "{cm:Pushto}"; Languages: ru; ExtraDiskSpaceRequired: 2493826
Name: "Languages\Romanian"; Description: "{cm:Romanian}"; Languages: ru; ExtraDiskSpaceRequired: 7957608
Name: "Languages\Russian"; Description: "{cm:Russian}"; Languages: ru; ExtraDiskSpaceRequired: 39371802
Name: "Languages\Sanskrit"; Description: "{cm:Sanskrit}"; Languages: ru; ExtraDiskSpaceRequired: 22747749
Name: "Languages\Serbian"; Description: "{cm:Serbian}"; Languages: ru; ExtraDiskSpaceRequired: 4611681
Name: "Languages\Sinhala"; Description: "{cm:Sinhala}"; Languages: ru; ExtraDiskSpaceRequired: 6793740
Name: "Languages\Syriac"; Description: "{cm:Syriac}"; Languages: ru; ExtraDiskSpaceRequired: 2734020
Name: "Languages\Slovak"; Description: "{cm:Slovak}"; Languages: ru; ExtraDiskSpaceRequired: 9126966
Name: "Languages\Slovenian"; Description: "{cm:Slovenian}"; Languages: ru; ExtraDiskSpaceRequired: 6824064
Name: "Languages\Middle_English"; Description: "{cm:Middle_English}"; Languages: ru; ExtraDiskSpaceRequired: 2105888
Name: "Languages\Middle_French"; Description: "{cm:Middle_French}"; Languages: ru; ExtraDiskSpaceRequired: 15831815
Name: "Languages\Swahili"; Description: "{cm:Swahili}"; Languages: ru; ExtraDiskSpaceRequired: 3861506
Name: "Languages\Tagalog"; Description: "{cm:Tagalog}"; Languages: ru; ExtraDiskSpaceRequired: 4114554
Name: "Languages\Tajik"; Description: "{cm:Tajik}"; Languages: ru; ExtraDiskSpaceRequired: 1119022
Name: "Languages\Thai"; Description: "{cm:Thai}"; Languages: ru; ExtraDiskSpaceRequired: 13565168
Name: "Languages\Tamil"; Description: "{cm:Tamil}"; Languages: ru; ExtraDiskSpaceRequired: 5118600
Name: "Languages\Telugu"; Description: "{cm:Telugu}"; Languages: ru; ExtraDiskSpaceRequired: 39318860
Name: "Languages\Tibetan"; Description: "{cm:Tibetan}"; Languages: ru; ExtraDiskSpaceRequired: 25231676
Name: "Languages\Tigrinya"; Description: "{cm:Tigrinya}"; Languages: ru; ExtraDiskSpaceRequired: 1806235
Name: "Languages\Turkish"; Description: "{cm:Turkish}"; Languages: ru; ExtraDiskSpaceRequired: 14069931
Name: "Languages\Uzbek"; Description: "{cm:Uzbek}"; Languages: ru; ExtraDiskSpaceRequired: 4286554
Name: "Languages\Uighur"; Description: "{cm:Uighur}"; Languages: ru; ExtraDiskSpaceRequired: 2017575
Name: "Languages\Ukrainian"; Description: "{cm:Ukrainian}"; Languages: ru; ExtraDiskSpaceRequired: 8043189
Name: "Languages\Urdu"; Description: "{cm:Urdu}"; Languages: ru; ExtraDiskSpaceRequired: 4825658
Name: "Languages\Finnish"; Description: "{cm:Finnish}"; Languages: ru; ExtraDiskSpaceRequired: 13274908
Name: "Languages\Frankish"; Description: "{cm:Frankish}"; Languages: ru; ExtraDiskSpaceRequired: 16451109
Name: "Languages\French"; Description: "{cm:French}"; Languages: ru; ExtraDiskSpaceRequired: 37350210
Name: "Languages\Hindi"; Description: "{cm:Hindi}"; Languages: ru; ExtraDiskSpaceRequired: 22717250
Name: "Languages\Croatian"; Description: "{cm:Croatian}"; Languages: ru; ExtraDiskSpaceRequired: 9135966
Name: "Languages\Cherokee"; Description: "{cm:Cherokee}"; Languages: ru; ExtraDiskSpaceRequired: 1083194
Name: "Languages\Czech"; Description: "{cm:Czech}"; Languages: ru; ExtraDiskSpaceRequired: 11896327
Name: "Languages\Swedish"; Description: "{cm:Swedish}"; Languages: ru; ExtraDiskSpaceRequired: 9460295
Name: "Languages\Esperanto"; Description: "{cm:Esperanto}"; Languages: ru; ExtraDiskSpaceRequired: 6602178
Name: "Languages\Estonian"; Description: "{cm:Estonian}"; Languages: ru; ExtraDiskSpaceRequired: 9644486
Name: "Languages\Javanese"; Description: "{cm:Javanese}"; Languages: ru; ExtraDiskSpaceRequired: 4404351
Name: "Languages\Japanese"; Description: "{cm:Japanese}"; Languages: ru; ExtraDiskSpaceRequired: 33072615

View File

@ -0,0 +1,30 @@
[Files]
Source: "tessdata\ara.*"; DestDir: "{app}\tessdata"; Components: Languages\Arabic; Flags: ignoreversion;
Source: "tessdata\chi_sim.*"; DestDir: "{app}\tessdata"; Components: Languages\Chineese_simplified; Flags: ignoreversion;
Source: "tessdata\eng.*"; DestDir: "{app}\tessdata"; Components: Languages\English; Flags: ignoreversion;
Source: "tessdata\fra.*"; DestDir: "{app}\tessdata"; Components: Languages\French; Flags: ignoreversion;
Source: "tessdata\deu.*"; DestDir: "{app}\tessdata"; Components: Languages\German; Flags: ignoreversion;
Source: "tessdata\jpn.*"; DestDir: "{app}\tessdata"; Components: Languages\Japanese; Flags: ignoreversion;
Source: "tessdata\rus.*"; DestDir: "{app}\tessdata"; Components: Languages\Russian; Flags: ignoreversion;
Source: "tessdata\spa.*"; DestDir: "{app}\tessdata"; Components: Languages\Spanish; Flags: ignoreversion;
[Components]
Name: "Languages"; Description: "{cm:Languages}"; Types: custom
Name: "Languages\Arabic"; Description: "{cm:Arabic}"; Languages: en; Types: custom; ExtraDiskSpaceRequired: 28534834
Name: "Languages\Chineese_simplified"; Description: "{cm:Chineese_simplified}"; Languages: en; Types: custom; ExtraDiskSpaceRequired: 42089623
Name: "Languages\English"; Description: "{cm:English}"; Languages: en; Types: custom; ExtraDiskSpaceRequired: 38371506
Name: "Languages\French"; Description: "{cm:French}"; Languages: en; Types: custom; ExtraDiskSpaceRequired: 37350210
Name: "Languages\German"; Description: "{cm:German}"; Languages: en; Types: custom; ExtraDiskSpaceRequired: 13367187
Name: "Languages\Japanese"; Description: "{cm:Japanese}"; Languages: en; Types: custom; ExtraDiskSpaceRequired: 33072615
Name: "Languages\Russian"; Description: "{cm:Russian}"; Languages: en; Types: custom; ExtraDiskSpaceRequired: 39371802
Name: "Languages\Spanish"; Description: "{cm:Spanish}"; Languages: en; Types: custom; ExtraDiskSpaceRequired: 39171233
Name: "Languages\English"; Description: "{cm:English}"; Languages: ru; Types: custom; ExtraDiskSpaceRequired: 38371506
Name: "Languages\Arabic"; Description: "{cm:Arabic}"; Languages: ru; Types: custom; ExtraDiskSpaceRequired: 28534834
Name: "Languages\Spanish"; Description: "{cm:Spanish}"; Languages: ru; Types: custom; ExtraDiskSpaceRequired: 39171233
Name: "Languages\Chineese_simplified"; Description: "{cm:Chineese_simplified}"; Languages: ru; Types: custom; ExtraDiskSpaceRequired: 42089623
Name: "Languages\German"; Description: "{cm:German}"; Languages: ru; Types: custom; ExtraDiskSpaceRequired: 13367187
Name: "Languages\Russian"; Description: "{cm:Russian}"; Languages: ru; Types: custom; ExtraDiskSpaceRequired: 39371802
Name: "Languages\French"; Description: "{cm:French}"; Languages: ru; Types: custom; ExtraDiskSpaceRequired: 37350210
Name: "Languages\Japanese"; Description: "{cm:Japanese}"; Languages: ru; Types: custom; ExtraDiskSpaceRequired: 33072615

View File

@ -1,28 +0,0 @@
Copyright 2008, Google Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

File diff suppressed because it is too large Load Diff

14813
external/gtest/gtest.h vendored

File diff suppressed because it is too large Load Diff

View File

@ -1,22 +0,0 @@
Copyright 2013-2014 RAD Game Tools and Valve Software
Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

7657
external/miniz/miniz.c vendored

File diff suppressed because it is too large Load Diff

1338
external/miniz/miniz.h vendored

File diff suppressed because it is too large Load Diff

View File

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

Before

Width:  |  Height:  |  Size: 97 KiB

After

Width:  |  Height:  |  Size: 97 KiB

35
main.cpp Normal file
View File

@ -0,0 +1,35 @@
#ifdef Q_OS_LINUX
# include <locale.h>
#endif
#include <QApplication>
#include <QTranslator>
#include <qtsingleapplication.h>
#include <Manager.h>
#include <Settings.h>
int main (int argc, char *argv[]) {
QtSingleApplication a (argc, argv);
if (a.sendMessage (QString ())) {
return 0;
}
#ifdef Q_OS_LINUX
setlocale (LC_NUMERIC, "C");
#endif
a.setQuitOnLastWindowClosed (false);
a.setApplicationName (settings_values::appName);
a.setOrganizationName (settings_values::companyName);
QTranslator translator;
// Set default to english.
if (translator.load (QLocale::system (), "translation", "_", ":/translations") ||
translator.load (":/translations/translation_en")) {
a.installTranslator (&translator);
}
Manager manager;
return a.exec ();
}

View File

@ -1,16 +0,0 @@
<RCC>
<qresource prefix="/icons">
<file alias="app.png">share/images/STIconBlue.png</file>
<file alias="st_success.png">share/images/STIconGreen.png</file>
<file alias="st_busy.png">share/images/STIconOrange.png</file>
<file alias="st_error.png">share/images/STIconRed.png</file>
<file alias="loadImages.png">share/images/loadImages.png</file>
<file alias="loadImages@2x.png">share/images/loadImages@2x.png</file>
<file alias="debug.png">share/images/debug.png</file>
<file alias="debug@2x.png">share/images/debug@2x.png</file>
</qresource>
<qresource prefix="/translations">
<file alias="screentranslator_ru.qm">share/translations/screentranslator_ru.qm</file>
<file alias="screentranslator_he.qm">share/translations/screentranslator_he.qm</file>
</qresource>
</RCC>

View File

@ -1,142 +0,0 @@
QT = core gui widgets network webenginewidgets
TARGET = screen-translator
TEMPLATE = app
CONFIG += c++17
DEPS_DIR=$$(ST_DEPS_DIR)
isEmpty(DEPS_DIR):DEPS_DIR=$$PWD/../deps
INCLUDEPATH += $$DEPS_DIR/include
LIBS += -L$$DEPS_DIR/lib
LIBS += -lhunspell -lleptonica -ltesseract
win32{
LIBS += -lUser32
}
linux{
QT += x11extras
LIBS += -lX11
}
SOURCES += $$PWD/external/miniz/miniz.c
INCLUDEPATH += $$PWD/external
VER=3.3.0
DEFINES += VERSION="$$VER"
VERSION = $$VER.0
QMAKE_TARGET_COMPANY = Gres
QMAKE_TARGET_PRODUCT = Screen Translator
QMAKE_TARGET_COPYRIGHT = Copyright (c) Gres
RC_ICONS = $$PWD/share/images/icon.ico
INCLUDEPATH += src src/service src/capture src/ocr \
src/represent src/translate src/correct
HEADERS += \
src/capture/capturearea.h \
src/capture/captureareaeditor.h \
src/capture/captureareaselector.h \
src/capture/capturer.h \
src/commonmodels.h \
src/correct/corrector.h \
src/correct/correctorworker.h \
src/correct/hunspellcorrector.h \
src/languagecodes.h \
src/manager.h \
src/ocr/recognizer.h \
src/ocr/recognizerworker.h \
src/ocr/tesseract.h \
src/represent/representer.h \
src/represent/resulteditor.h \
src/represent/resultwidget.h \
src/service/apptranslator.h \
src/service/debug.h \
src/service/geometryutils.h \
src/service/globalaction.h \
src/service/keysequenceedit.h \
src/service/runatsystemstart.h \
src/service/singleapplication.h \
src/service/updates.h \
src/service/widgetstate.h \
src/settings.h \
src/settingseditor.h \
src/settingsvalidator.h \
src/stfwd.h \
src/substitutionstable.h \
src/task.h \
src/translate/translator.h \
src/translate/webpage.h \
src/translate/webpageproxy.h \
src/trayicon.h
SOURCES += \
src/capture/capturearea.cpp \
src/capture/captureareaeditor.cpp \
src/capture/captureareaselector.cpp \
src/capture/capturer.cpp \
src/commonmodels.cpp \
src/correct/corrector.cpp \
src/correct/correctorworker.cpp \
src/correct/hunspellcorrector.cpp \
src/languagecodes.cpp \
src/main.cpp \
src/manager.cpp \
src/ocr/recognizer.cpp \
src/ocr/recognizerworker.cpp \
src/ocr/tesseract.cpp \
src/represent/representer.cpp \
src/represent/resulteditor.cpp \
src/represent/resultwidget.cpp \
src/service/apptranslator.cpp \
src/service/debug.cpp \
src/service/geometryutils.cpp \
src/service/globalaction.cpp \
src/service/keysequenceedit.cpp \
src/service/runatsystemstart.cpp \
src/service/singleapplication.cpp \
src/service/updates.cpp \
src/service/widgetstate.cpp \
src/settings.cpp \
src/settingseditor.cpp \
src/settingsvalidator.cpp \
src/substitutionstable.cpp \
src/translate/translator.cpp \
src/translate/webpage.cpp \
src/translate/webpageproxy.cpp \
src/trayicon.cpp
RESOURCES += \
recources.qrc
FORMS += \
src/settingseditor.ui
OTHER_FILES += \
translators/*.js \
version.json \
updates.json
TRANSLATIONS += \
share/translations/screentranslator_ru.ts \
share/translations/screentranslator_he.ts
linux {
PREFIX = /usr
target.path = $$PREFIX/bin
shortcuts.files = $$PWD/share/screentranslator.desktop
shortcuts.path = $$PREFIX/share/applications/
pixmaps.files += $$PWD/share/images/screentranslator.png
pixmaps.path = $$PREFIX/share/icons/hicolor/128x128/apps/
INSTALLS += target shortcuts pixmaps
}
win32 {
RC_ICONS = $$PWD/share/images/icon.ico
target.path = /
INSTALLS += target
}
mac {
ICON = $$PWD/share/images/icon.icns
}

8
scripts/get_deps.sh Executable file
View File

@ -0,0 +1,8 @@
#!/bin/bash
source ./options.sh $@
echo "Downloading dependencies"
wget -O $DOWNLOAD_DIR/leptonica.tar.gz http://www.leptonica.com/source/leptonica-1.72.tar.gz
wget -O $DOWNLOAD_DIR/tesseract.tar.gz https://github.com/tesseract-ocr/tesseract/archive/3.04.00.tar.gz

14
scripts/get_tessdata.sh Executable file
View File

@ -0,0 +1,14 @@
#!/bin/bash
source ./options.sh $@
echo "Downloading and extracting tessdata"
wget -O $DOWNLOAD_DIR/tessdata.tar.gz https://github.com/tesseract-ocr/tessdata/archive/3.04.00.tar.gz
EXTRACT_DIR=$DOWNLOAD_DIR/tessdata
CLEAN=true
cleanupDirInNeeded $EXTRACT_DIR
tar zxf $DOWNLOAD_DIR/tessdata.tar.gz -C $EXTRACT_DIR
EXTRACTED=`ls $EXTRACT_DIR | grep tess`
mv $EXTRACT_DIR/$EXTRACTED/* $EXTRACT_DIR
rm -r $EXTRACT_DIR/$EXTRACTED

5
scripts/install_deps.sh Executable file
View File

@ -0,0 +1,5 @@
#!/bin/bash
sudo apt-get update -q
sudo apt-get -y install libxcb-util0-dev fakeroot libtesseract-dev libleptonica-dev qt5-qmake libqt5webkit5-dev libqt5x11extras5-dev qttools5-dev-tools g++
#sudo apt-get -y install tesseract-ocr-eng #for testing

19
scripts/make_all.sh Executable file
View File

@ -0,0 +1,19 @@
#!/bin/bash
source ./options.sh $@
#cleanupDirInNeeded $WORK_DIR
echo "Running all scripts for $PLATFORM"
#./install_deps $@
#./get_tessdata.sh $@
#./get_deps.sh $@
#./make_deps.sh $@
./make_app.sh $@
if [ "$PLATFORM" == "linux" ]; then
./make_deb.sh $@
fi
if [ "$PLATFORM" == "mingw" ]; then
./make_iss.sh $@
fi
./make_sf.sh $@
echo "All scripts successfully run"

12
scripts/make_app.sh Executable file
View File

@ -0,0 +1,12 @@
#!/bin/bash
source ./options.sh $@
cleanupDirInNeeded $APP_DIR
cd $APP_DIR
echo "Building app"
$QT_LRELEASE $QT_CHOOSER $SRC_DIR/ScreenTranslator.pro
$QMAKE $QT_CHOOSER "CONFIG-=debug_and_release" "CONFIG+=release" $SRC_DIR
make $JOBS

59
scripts/make_deb.sh Executable file
View File

@ -0,0 +1,59 @@
#!/bin/bash
source ./options.sh $@
U_VER="15.04"
for arg in ${@}; do
case "$arg" in
"15.10" ) U_VER=$arg;;
esac
done
cleanupDirInNeeded $DEB_DIR
cp -r $SRC_DISTR_DIR/deb/* $DEB_DIR
INSTALL_DIR=/opt/ScreenTranslator
function makeChangelog {
local FOUND=false
local CHANGELOG="screen-translator ($VERSION) stable; urgency=medium\n\n"
while read line; do
if [[ $line =~ [0-9]+\.[0-9]+\.[0-9]+: ]]; then #version info
if [ "$line" == "$VERSION:" ]; then
FOUND=true
continue
elif [ $FOUND == true ]; then
break;
fi
fi
if [ $FOUND == true ]; then
CHANGELOG="$CHANGELOG$line\n\n"
fi
done < $SRC_DISTR_DIR/Changelog_en.txt
CHANGELOG="$CHANGELOG--Gres <translator@gres.biz> `date -R`\n\n"
echo $CHANGELOG
}
echo "Making deb"
cp $SRC_DIR/LICENSE.md $DEB_DIR/DEBIAN/copyright
mkdir -p $DEB_DIR/usr/share/pixmaps/
cp $SRC_DIR/images/STIconBlue.png $DEB_DIR/usr/share/pixmaps/ScreenTranslator.png
mkdir -p $DEB_DIR/$INSTALL_DIR/
cp $APP_DIR/ScreenTranslator $DEB_DIR/$INSTALL_DIR/ScreenTranslator
$STRIP -s $DEB_DIR/$INSTALL_DIR/ScreenTranslator
cp -r $SRC_DIR/translators $DEB_DIR/$INSTALL_DIR/translators
VERSION=`grep "versionString" $SRC_DIR/version.json | cut -d'"' -f4`
sed "s/Version:.*\+/Version: $VERSION/" -i $DEB_DIR/DEBIAN/control
sed "s/Version=.*\+/Version=$VERSION/" -i $DEB_DIR/usr/share/applications/ScreenTranslator.desktop
SIZE=$(expr `du -bs $DEB_DIR | cut -f1` / 1024)
sed "s/Installed-Size:.*\+/Installed-Size: $SIZE/" -i $DEB_DIR/DEBIAN/control
echo -e $(makeChangelog) > $DEB_DIR/DEBIAN/changelog
if [ "$U_VER" == "15.10" ]; then
sed "s/libtesseract3/libtesseract3v5/" -i $DEB_DIR/DEBIAN/control
fi
fakeroot dpkg-deb --build $DEB_DIR $WORK_DIR/screen-translator-$VERSION-$U_VER.deb

54
scripts/make_deps.sh Executable file
View File

@ -0,0 +1,54 @@
#!/bin/bash
source ./options.sh $@
BUILD_LEPT=false
BUILD_TESS=false
for arg in ${@}; do
case "$arg" in
"tess" ) BUILD_TESS=true;;
"lept" ) BUILD_LEPT=true;;
esac
done
if ! $BUILD_LEPT && ! $BUILD_TESS ; then
BUILD_LEPT=true
BUILD_TESS=true
fi
cleanupDirInNeeded $DEPS_DIR
if $BUILD_LEPT ; then
echo "Building Leptonica"
tar zxf $DOWNLOAD_DIR/leptonica.tar.gz -C $DEPS_DIR
LEPT_DIR=`ls $DEPS_DIR | grep lept`
pushd .
cd $DEPS_DIR/$LEPT_DIR
$CFLAGS ./configure --prefix=$DEPS_DIR --disable-programs "$HOST_ATTR"
make $JOBS
make install
popd
fi
if $BUILD_TESS ; then
echo "Building Tesseract"
tar zxf $DOWNLOAD_DIR/tesseract.tar.gz -C $DEPS_DIR
TESS_DIR=`ls $DEPS_DIR | grep tess`
pushd .
cd $DEPS_DIR/$TESS_DIR
sed 's/vs2008/vs2010/g' -i ccutil/Makefile.in
sed 's/Windows\.h/windows\.h/g' -i opencl/openclwrapper.cpp
LIBLEPT_HEADERSDIR=$DEPS_DIR/include LIBS=-L$DEPS_DIR/lib ./configure --prefix=$DEPS_DIR --disable-tessdata-prefix "$HOST_ATTR"
make $JOBS
make install
popd
fi
if [ $PLATFORM == 'mingw' ]; then
find $DEPS_DIR -name '*.dll' -exec cp {} $DEPS_DIR/lib \;
fi
echo "Done"

49
scripts/make_iss.sh Executable file
View File

@ -0,0 +1,49 @@
#!/bin/bash
source ./options.sh $@
cleanupDirInNeeded $ISS_DIR
cp -r $SRC_DISTR_DIR/iss/* $ISS_DIR
CONTENT_DIR=$ISS_DIR/content
mkdir -p $CONTENT_DIR
echo "Making ISS"
TESSDATA_DIR="$DOWNLOAD_DIR/tessdata"
$(cd $ISS_DIR && ./make_tess_iss.sh $TESSDATA_DIR out="$ISS_DIR/tessdata.iss")
#setup
VERSION=`grep "versionString" $SRC_DIR/version.json | cut -d'"' -f4`
sed "s/#define MyAppVersion.*$/#define MyAppVersion \"$VERSION\"/" -i $ISS_DIR/InnoSetup.iss
cp $SRC_DIR/images/icon.ico $ISS_DIR/icon.ico
cp $SRC_DIR/LICENSE.md $ISS_DIR/LICENSE_en.md
cp $SRC_DISTR_DIR/Changelog_en.txt $ISS_DIR/Changelog_en.txt
cp $SRC_DISTR_DIR/Changelog_ru.txt $ISS_DIR/Changelog_ru.txt
#app
cp $APP_DIR/ScreenTranslator.exe $CONTENT_DIR/ScreenTranslator.exe
cp -r $SRC_DIR/translators $CONTENT_DIR/translators
#libs
QT_LIBS="Qt5WebKitWidgets Qt5Widgets Qt5WebKit Qt5Gui Qt5Network Qt5Core Qt5Sensors Qt5Positioning Qt5PrintSupport
Qt5OpenGL Qt5Sql Qt5Quick Qt5Qml Qt5WebChannel Qt5Multimedia Qt5MultimediaWidgets"
for i in $QT_LIBS; do
cp -d $QT_LIB_DIR/$i.dll $CONTENT_DIR
done
mkdir -p $CONTENT_DIR/platforms
cp -d $QT_LIB_DIR/../plugins/platforms/qwindows.dll $CONTENT_DIR/platforms
MINGW_LIBS="libgcc_s_sjlj-1 libstdc++-6 icuin55 icuuc55 icudt55 libwinpthread-1 ssleay32 libeay32"
for i in $MINGW_LIBS; do
cp -d $MINGW_DIR/lib/$i.dll $CONTENT_DIR
done
cp -d $DEPS_DIR/lib/liblept*.dll $CONTENT_DIR
cp -d $DEPS_DIR/lib/libtesseract*.dll $CONTENT_DIR
find $CONTENT_DIR -name '*.exe' -exec $STRIP -s {} \;
find $CONTENT_DIR -name '*.dll' -exec $STRIP -s {} \;
cd $ISS_DIR
wine "C:\Program Files\Inno Setup 5\iscc.exe" "InnoSetup.iss"

21
scripts/make_sf.sh Executable file
View File

@ -0,0 +1,21 @@
#!/bin/bash
source ./options.sh $@
cleanupDirInNeeded $SF_DIR
echo "Making SF"
function format {
local FILE=$1
sed "s/\(Changes\)/#\1/g" -i $FILE
sed "s/\(Изменения\)/#\1/g" -i $FILE
sed "s/\([0-9]\+\.[0-9]\+\.[0-9]\+:\)/##\1/g" -i $FILE
sed "s/+\s/* /g" -i $FILE
sed "s/-\s/* /g" -i $FILE
}
cp -f $SRC_DISTR_DIR/Changelog_en.txt $SF_DIR/readme.md
format $SF_DIR/readme.md
cp -f $SRC_DISTR_DIR/Changelog_ru.txt $SF_DIR/readme_ru.md
iconv -f cp1251 -t utf8 $SF_DIR/readme_ru.md -o $SF_DIR/readme_ru.md.u
mv $SF_DIR/readme_ru.md.u $SF_DIR/readme_ru.md
format $SF_DIR/readme_ru.md

58
scripts/options.sh Executable file
View File

@ -0,0 +1,58 @@
#!/bin/bash
set -e
PLATFORM=linux
CLEAN=false
JOBS=""
QT_CHOOSER="-qt=qt5"
QMAKE=qmake
QT_LRELEASE=lrelease
QT_LIB_DIR=/usr/lib/x86_64-linux-gnu
STRIP=strip
for arg in ${@}; do
case "$arg" in
"linux" ) PLATFORM=linux;;
"mingw" ) PLATFORM=mingw;;
"clean" ) CLEAN=true;;
"-j"* ) JOBS=$arg;;
*"qmake" ) QMAKE=$arg
QT_LRELEASE=`readlink -e $(dirname $arg)/lrelease`
QT_LIB_DIR=`readlink -e $(dirname $arg)/../lib`
QT_CHOOSER=""
;;
esac
done
WORK_DIR=../../build/$PLATFORM
MINGW_DIR=/opt/mingw-4.9.3/mingw-w64-i686
if [ "$PLATFORM" == "mingw" ]; then
QT_LIB_DIR=`readlink -e $QT_LIB_DIR/../bin`
HOST=i686-w64-mingw32
HOST_ATTR="--host=$HOST"
STRIP=$HOST-strip
export PATH="$MINGW_DIR/bin:$PATH"
COMPILERS="CC=\"${HOST}-gcc\" AR=\"${HOST}-ar\" RANLIB=\"${HOST}-ranlib\""
fi
WORK_DIR=`readlink -m $WORK_DIR`
DEPS_DIR=`readlink -m $WORK_DIR/deps`
APP_DIR=`readlink -m $WORK_DIR/app`
DEB_DIR=`readlink -m $WORK_DIR/deb`
ISS_DIR=`readlink -m $WORK_DIR/iss`
SF_DIR=`readlink -m $WORK_DIR/sf`
DOWNLOAD_DIR=`readlink -m ../../`
SRC_DIR=`readlink -e ..`
SRC_DISTR_DIR=$SRC_DIR/distr
mkdir -p $WORK_DIR
function cleanupDirInNeeded {
local DIR=$1
if [[ "$CLEAN" == "true" && -d "$DIR" ]]; then
rm -rf $DIR
fi
mkdir -p $DIR
}

61
scripts/win/build.bat Normal file
View File

@ -0,0 +1,61 @@
@echo off
set SELF_PATH=%~dp0
call %SELF_PATH%\env.bat
::build
rmdir /q /s build
set ROOT=%SELF_PATH%\..\..
lrelease %ROOT%\ScreenTranslator.pro
mkdir build
cd build
qmake INCLUDEPATH+=%cd%\..\installed\include LIBS+=-L%cd%\..\installed\bin LIBS+=-L%cd%\..\installed\lib %ROOT%
nmake
cd ..
if %errorlevel% neq 0 exit /b %errorlevel%
::pack
rmdir /q /s iss
mkdir iss
copy /Y %ROOT%\distr\iss\* iss
copy /Y %ROOT%\distr\Changelog_en.txt iss\
copy /Y %ROOT%\distr\Changelog_ru.txt iss\
copy /Y %ROOT%\LICENSE.md iss\LICENSE_en.md
copy /Y %ROOT%\images\icon.ico iss\icon.ico
mkdir iss\content
copy /Y build\release\ScreenTranslator.exe iss\content\ScreenTranslator.exe
copy /Y installed\bin\*.dll iss\content
copy /Y c:\OpenSSL-Win32\bin\libeay32.dll iss\content
copy /Y c:\OpenSSL-Win32\bin\ssleay32.dll iss\content
mkdir iss\content\translations
copy /Y %ROOT%\translations\*.qm iss\content\translations
mkdir iss\content\translators
copy /Y %ROOT%\translators\* iss\content\translators
windeployqt --release iss\content\ScreenTranslator.exe
for /f "delims=" %%i in ('findstr versionString %ROOT%\version.json') do set VERSION_LINE=%%i
set UNQUOTED=%VERSION_LINE:"='%
for /f "tokens=4 delims='" %%i in ("%UNQUOTED%") do set VERSION=%%i
echo #define MyAppVersion "%VERSION%" > iss\defines.iss
cd iss
iscc.exe InnoSetup.iss
cd ..
if "%WITH_TESSDATA%" == "" goto end
mkdir iss\tessdata
copy /Y download\tessdata\* iss\tessdata
cd iss
iscc.exe InnoSetupWithTessdata.iss
cd ..
:end

33
scripts/win/deploy_sf.bat Normal file
View File

@ -0,0 +1,33 @@
@echo off
set PATH=c:\Program Files (x86)\WinSCP\;%PATH%
set SELF_PATH=%~dp0
set ROOT=%SELF_PATH%\..\..
for /f "delims=" %%i in ('findstr versionString %ROOT%\version.json') do set VERSION_LINE=%%i
set UNQUOTED=%VERSION_LINE:"='%
for /f "tokens=4 delims='" %%i in ("%UNQUOTED%") do set VERSION=%%i
for /f "delims=" %%i in ('dir /b screen-translator-online*.exe') do set online=%%i
for /f "delims=" %%i in ('dir /b screen-translator-offline*.exe') do set offline=%%i
winscp.com /keygen %SELF_PATH%\sf_key /output=key.ppk
set folder="/home/frs/project/screen-translator/bin/v%VERSION%"
set bin_folder="/home/frs/project/screen-translator/bin"
winscp.com /command "open sftp://onemoregres@frs.sourceforge.net/ -privatekey=key.ppk -hostkey=*" ^
"mkdir %folder%" ^
"put %online% %folder%/%online%" ^
"put %offline% %folder%/%offline%" ^
"put %ROOT%\distr\Changelog_ru.txt %bin_folder%/readme_ru.md" ^
"put %ROOT%\distr\Changelog_en.txt %bin_folder%/readme.md" ^
"exit"
set url="https://sourceforge.net/projects/screen-translator/files/bin/v%VERSION%/%online%"
curl --insecure -H "Accept: application/json" -X PUT -d "default=windows" -d "api_key=%sf_api%" %url%
set url="https://sourceforge.net/projects/screen-translator/files/bin/v%VERSION%/%offline%"
curl --insecure -H "Accept: application/json" -X PUT -d "default=windows" -d "api_key=%sf_api%" %url%

19
scripts/win/env.bat Normal file
View File

@ -0,0 +1,19 @@
@echo off
if "%ARCH%" == "" set ARCH=x86
if /i %ARCH% == x86 goto x86
if /i %ARCH% == x64 goto x64
goto end
:x64
call "c:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" amd64
set PATH=c:\Qt\5.5\msvc2013_64\bin\;c:\Program Files (x86)\NSIS\;C:\Program Files (x86)\Inno Setup 5;C:\Program Files\CMake\bin;%PATH%
goto end
:x86
call "c:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" x86
set PATH=c:\Qt\5.5\msvc2013\bin\;c:\Program Files (x86)\NSIS\;C:\Program Files (x86)\Inno Setup 5;C:\Program Files\CMake\bin;%PATH%
goto end
:end

111
scripts/win/prepare.bat Normal file
View File

@ -0,0 +1,111 @@
@echo off
set SELF_PATH=%~dp0
call %SELF_PATH%\env.bat
rem choco install curl cmake
mkdir download
if "%WITH_TESSDATA%" == "" goto libs
echo "Downloading tessdata"
mkdir download\tessdata
cd download\tessdata
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/ara.cube.bigrams
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/ara.cube.fold
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/ara.cube.lm
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/ara.cube.nn
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/ara.cube.params
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/ara.cube.size
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/ara.cube.word-freq
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/ara.traineddata
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/chi_sim.traineddata
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/deu.traineddata
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/eng.cube.bigrams
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/eng.cube.fold
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/eng.cube.lm
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/eng.cube.nn
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/eng.cube.params
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/eng.cube.size
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/eng.cube.word-freq
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/eng.tesseract_cube.nn
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/eng.traineddata
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/fra.cube.bigrams
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/fra.cube.fold
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/fra.cube.lm
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/fra.cube.nn
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/fra.cube.params
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/fra.cube.size
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/fra.cube.word-freq
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/fra.tesseract_cube.nn
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/fra.traineddata
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/frk.traineddata
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/frm.traineddata
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/jpn.traineddata
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/rus.cube.fold
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/rus.cube.lm
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/rus.cube.nn
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/rus.cube.params
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/rus.cube.size
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/rus.cube.word-freq
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/rus.traineddata
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/spa.cube.bigrams
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/spa.cube.fold
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/spa.cube.lm
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/spa.cube.nn
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/spa.cube.params
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/spa.cube.size
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/spa.cube.word-freq
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/spa.traineddata
curl -fsSLk -O https://github.com/tesseract-Ocr/tessdata/raw/3.04.00/spa_old.traineddata
cd ..\..
:libs
if "%CLEAR_CACHE%" == "" goto build-libs
echo "Clearing cache"
rmdir /s /q leptonica
rmdir /s /q leptonica-build
rmdir /s /q tesseract
rmdir /s /q leptonica-build
rmdir /s /q installed
:build-libs
if exist installed\bin\tesseract*.dll goto end
echo "Downloading dependencies"
if not exist download\leptonica.zip (
curl -fsSLk -o download\leptonica.zip https://github.com/DanBloomberg/leptonica/archive/1.74.4.zip
)
if not exist download\tesseract.zip (
curl -fsSLk -o download\tesseract.zip https://github.com/tesseract-Ocr/tesseract/archive/3.05.01.zip
)
echo "Building dependencies"
unzip -qq download\leptonica.zip
move leptonica* leptonica
mkdir leptonica-build
cd leptonica-build
cmake -DCMAKE_BUILD_TYPE=Release -DTARGET_CPU=%ARCH% -DCMAKE_INSTALL_PREFIX=..\installed ..\leptonica
cmake --build . --config Release
cmake --build . --config Release --target install
cd ..
copy /y /b installed\lib\leptonica*.lib installed\lib\lept.lib
if %errorlevel% neq 0 exit /b %errorlevel%
unzip -qq download\tesseract.zip
move tesseract* tesseract
mkdir tesseract-build
cd tesseract-build
cmake -DCMAKE_BUILD_TYPE=Release -DTARGET_CPU=%ARCH% -DCMAKE_INSTALL_PREFIX=..\installed -DCMAKE_PREFIX_PATH=..\installed ..\tesseract
cmake --build . --config Release
cmake --build . --config Release --target install
cd ..
copy /y /b installed\lib\tesseract*.lib installed\lib\tesseract.lib
if %errorlevel% neq 0 exit /b %errorlevel%
:end

Some files were not shown because too many files have changed in this diff Show More