mirror of https://github.com/JakubMelka/PDF4QT.git
Audio book tool - voices
This commit is contained in:
parent
16b583f390
commit
e5e37b3283
|
@ -31,3 +31,4 @@ PdfForQtViewer.depends = PdfForQtLib
|
|||
JBIG2_Viewer.depends = PdfForQtLib
|
||||
PDFExampleGenerator.depends = PdfForQtLib
|
||||
CodeGenerator.depends = PdfForQtLib
|
||||
PdfTool.depends = PdfForQtLib
|
||||
|
|
|
@ -43,6 +43,7 @@ SOURCES += \
|
|||
pdfoutputformatter.cpp \
|
||||
pdftoolabstractapplication.cpp \
|
||||
pdftoolattachments.cpp \
|
||||
pdftoolaudiobook.cpp \
|
||||
pdftoolfetchtext.cpp \
|
||||
pdftoolinfo.cpp \
|
||||
pdftoolinfojavascript.cpp \
|
||||
|
@ -66,6 +67,7 @@ HEADERS += \
|
|||
pdfoutputformatter.h \
|
||||
pdftoolabstractapplication.h \
|
||||
pdftoolattachments.h \
|
||||
pdftoolaudiobook.h \
|
||||
pdftoolfetchtext.h \
|
||||
pdftoolinfo.h \
|
||||
pdftoolinfojavascript.h \
|
||||
|
|
|
@ -115,7 +115,9 @@ public:
|
|||
ErrorDocumentReading,
|
||||
ErrorInvalidArguments,
|
||||
ErrorFailedWriteToFile,
|
||||
ErrorPermissions
|
||||
ErrorPermissions,
|
||||
ErrorCOM,
|
||||
ErrorSAPI
|
||||
};
|
||||
|
||||
enum StandardString
|
||||
|
|
|
@ -0,0 +1,259 @@
|
|||
// Copyright (C) 2020 Jakub Melka
|
||||
//
|
||||
// This file is part of PdfForQt.
|
||||
//
|
||||
// PdfForQt is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// PdfForQt is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with PDFForQt. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "pdftoolaudiobook.h"
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
|
||||
#include <sapi.h>
|
||||
//#include <sphelper.h>
|
||||
|
||||
#pragma comment(lib, "ole32")
|
||||
|
||||
namespace pdftool
|
||||
{
|
||||
|
||||
static PDFToolAudioBook s_audioBookApplication;
|
||||
|
||||
PDFVoiceInfo::PDFVoiceInfo(std::map<QString, QString> properties, ISpVoice* voice) :
|
||||
m_properties(qMove(properties)),
|
||||
m_voice(voice)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
PDFVoiceInfo::~PDFVoiceInfo()
|
||||
{
|
||||
if (m_voice)
|
||||
{
|
||||
m_voice->Release();
|
||||
}
|
||||
}
|
||||
|
||||
QLocale PDFVoiceInfo::getLocale() const
|
||||
{
|
||||
bool ok = false;
|
||||
LCID locale = getLanguage().toInt(&ok, 16);
|
||||
|
||||
if (ok)
|
||||
{
|
||||
int count = GetLocaleInfoW(locale, LOCALE_SISO639LANGNAME, NULL, 0);
|
||||
std::vector<wchar_t> localeString(count, wchar_t());
|
||||
GetLocaleInfoW(locale, LOCALE_SISO639LANGNAME, localeString.data(), int(localeString.size()));
|
||||
QString isoCode = QString::fromWCharArray(localeString.data());
|
||||
return QLocale(isoCode);
|
||||
}
|
||||
|
||||
return QLocale();
|
||||
}
|
||||
|
||||
QString PDFVoiceInfo::getStringValue(QString key) const
|
||||
{
|
||||
auto it = m_properties.find(key);
|
||||
if (it != m_properties.cend())
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString PDFToolAudioBook::getStandardString(StandardString standardString) const
|
||||
{
|
||||
switch (standardString)
|
||||
{
|
||||
case Command:
|
||||
return "audio-book";
|
||||
|
||||
case Name:
|
||||
return PDFToolTranslationContext::tr("Audio book convertor");
|
||||
|
||||
case Description:
|
||||
return PDFToolTranslationContext::tr("Convert your document to a simple audio book.");
|
||||
|
||||
default:
|
||||
Q_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
int PDFToolAudioBook::execute(const PDFToolOptions& options)
|
||||
{
|
||||
if (!SUCCEEDED(::CoInitializeEx(nullptr, COINIT_MULTITHREADED | COINIT_SPEED_OVER_MEMORY)))
|
||||
{
|
||||
return ErrorCOM;
|
||||
}
|
||||
|
||||
int returnCode = showVoiceList(options);
|
||||
|
||||
::CoUninitialize();
|
||||
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
PDFToolAbstractApplication::Options PDFToolAudioBook::getOptionsFlags() const
|
||||
{
|
||||
return ConsoleFormat | OpenDocument | PageSelector | TextAnalysis;
|
||||
}
|
||||
|
||||
int PDFToolAudioBook::fillVoices(const PDFToolOptions& options, PDFVoiceInfoList& list, bool fillVoicePointers)
|
||||
{
|
||||
int result = ExitSuccess;
|
||||
|
||||
ISpObjectTokenCategory* category = nullptr;
|
||||
if (!SUCCEEDED(::CoCreateInstance(CLSID_SpObjectTokenCategory, NULL, CLSCTX_ALL, __uuidof(ISpObjectTokenCategory), (LPVOID*)&category)))
|
||||
{
|
||||
PDFConsole::writeError(PDFToolTranslationContext::tr("SAPI Error: Cannot enumerate SAPI voices."), options.outputCodec);
|
||||
return ErrorSAPI;
|
||||
}
|
||||
|
||||
if (!SUCCEEDED(category->SetId(SPCAT_VOICES, FALSE)))
|
||||
{
|
||||
PDFConsole::writeError(PDFToolTranslationContext::tr("SAPI Error: Cannot enumerate SAPI voices."), options.outputCodec);
|
||||
return ErrorSAPI;
|
||||
}
|
||||
|
||||
IEnumSpObjectTokens* enumTokensObject = nullptr;
|
||||
if (SUCCEEDED(category->EnumTokens(NULL, NULL, &enumTokensObject)))
|
||||
{
|
||||
ISpObjectToken* token = nullptr;
|
||||
while (SUCCEEDED(enumTokensObject->Next(1, &token, NULL)))
|
||||
{
|
||||
if (token)
|
||||
{
|
||||
/* Attributes can be for example:
|
||||
* Version,
|
||||
* Language,
|
||||
* Gender,
|
||||
* Age,
|
||||
* Name
|
||||
* Vendor */
|
||||
|
||||
std::map<QString, QString> properties;
|
||||
|
||||
ISpDataKey* attributes = nullptr;
|
||||
if (SUCCEEDED(token->OpenKey(L"Attributes", &attributes)))
|
||||
{
|
||||
for (ULONG i = 0; ; ++i)
|
||||
{
|
||||
LPWSTR valueName = NULL;
|
||||
if (SUCCEEDED(attributes->EnumValues(i, &valueName)))
|
||||
{
|
||||
LPWSTR data = NULL;
|
||||
if (SUCCEEDED(attributes->GetStringValue(valueName, &data)))
|
||||
{
|
||||
QString propertyName = QString::fromWCharArray(valueName);
|
||||
QString propertyValue = QString::fromWCharArray(data);
|
||||
if (!propertyValue.isEmpty())
|
||||
{
|
||||
properties[propertyName] = propertyValue;
|
||||
}
|
||||
::CoTaskMemFree(data);
|
||||
}
|
||||
|
||||
::CoTaskMemFree(valueName);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
attributes->Release();
|
||||
}
|
||||
|
||||
ISpVoice* voice = nullptr;
|
||||
if (fillVoicePointers)
|
||||
{
|
||||
token->QueryInterface(__uuidof(ISpVoice), (void**)&voice);
|
||||
}
|
||||
|
||||
list.emplace_back(qMove(properties), voice);
|
||||
|
||||
token->Release();
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PDFConsole::writeError(PDFToolTranslationContext::tr("SAPI Error: Cannot enumerate SAPI voices."), options.outputCodec);
|
||||
result = ErrorSAPI;
|
||||
}
|
||||
|
||||
if (enumTokensObject)
|
||||
{
|
||||
enumTokensObject->Release();
|
||||
}
|
||||
|
||||
if (category)
|
||||
{
|
||||
category->Release();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int PDFToolAudioBook::showVoiceList(const PDFToolOptions& options)
|
||||
{
|
||||
PDFVoiceInfoList voices;
|
||||
int result = fillVoices(options, voices, false);
|
||||
|
||||
PDFOutputFormatter formatter(options.outputStyle, options.outputCodec);
|
||||
formatter.beginDocument("voices", PDFToolTranslationContext::tr("Available voices for given settings:"));
|
||||
formatter.endl();
|
||||
|
||||
formatter.beginTable("voices", PDFToolTranslationContext::tr("Voice list"));
|
||||
|
||||
formatter.beginTableHeaderRow("header");
|
||||
formatter.writeTableHeaderColumn("name", PDFToolTranslationContext::tr("Name"), Qt::AlignLeft);
|
||||
formatter.writeTableHeaderColumn("gender", PDFToolTranslationContext::tr("Gender"), Qt::AlignLeft);
|
||||
formatter.writeTableHeaderColumn("age", PDFToolTranslationContext::tr("Age"), Qt::AlignLeft);
|
||||
formatter.writeTableHeaderColumn("language", PDFToolTranslationContext::tr("Language"), Qt::AlignLeft);
|
||||
formatter.writeTableHeaderColumn("locale", PDFToolTranslationContext::tr("Locale"), Qt::AlignLeft);
|
||||
formatter.writeTableHeaderColumn("vendor", PDFToolTranslationContext::tr("Vendor"), Qt::AlignLeft);
|
||||
formatter.writeTableHeaderColumn("version", PDFToolTranslationContext::tr("Version"), Qt::AlignLeft);
|
||||
formatter.endTableHeaderRow();
|
||||
|
||||
for (const PDFVoiceInfo& voice : voices)
|
||||
{
|
||||
formatter.beginTableRow("voice");
|
||||
formatter.writeTableHeaderColumn("name", voice.getName(), Qt::AlignLeft);
|
||||
formatter.writeTableHeaderColumn("gender", voice.getGender(), Qt::AlignLeft);
|
||||
formatter.writeTableHeaderColumn("age", voice.getAge(), Qt::AlignLeft);
|
||||
formatter.writeTableHeaderColumn("language", voice.getLanguage(), Qt::AlignLeft);
|
||||
formatter.writeTableHeaderColumn("locale", voice.getLocale().name(), Qt::AlignLeft);
|
||||
formatter.writeTableHeaderColumn("vendor", voice.getVendor(), Qt::AlignLeft);
|
||||
formatter.writeTableHeaderColumn("version", voice.getVersion(), Qt::AlignLeft);
|
||||
formatter.endTableRow();
|
||||
}
|
||||
|
||||
formatter.endTable();
|
||||
|
||||
formatter.endDocument();
|
||||
PDFConsole::writeText(formatter.getString(), options.outputCodec);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace pdftool
|
||||
|
||||
#endif
|
|
@ -0,0 +1,77 @@
|
|||
// Copyright (C) 2020 Jakub Melka
|
||||
//
|
||||
// This file is part of PdfForQt.
|
||||
//
|
||||
// PdfForQt is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// PdfForQt is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with PDFForQt. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef PDFTOOLAUDIOBOOK_H
|
||||
#define PDFTOOLAUDIOBOOK_H
|
||||
|
||||
#include "pdftoolabstractapplication.h"
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
|
||||
struct ISpVoice;
|
||||
|
||||
namespace pdftool
|
||||
{
|
||||
|
||||
class PDFVoiceInfo
|
||||
{
|
||||
public:
|
||||
PDFVoiceInfo() = default;
|
||||
PDFVoiceInfo(std::map<QString, QString> properties, ISpVoice* voice);
|
||||
|
||||
PDFVoiceInfo(const PDFVoiceInfo&) = delete;
|
||||
PDFVoiceInfo(PDFVoiceInfo&&) = default;
|
||||
PDFVoiceInfo& operator=(const PDFVoiceInfo&) = delete;
|
||||
PDFVoiceInfo& operator=(PDFVoiceInfo&&) = default;
|
||||
|
||||
~PDFVoiceInfo();
|
||||
|
||||
QString getName() const { return getStringValue("Name"); }
|
||||
QString getGender() const { return getStringValue("Gender"); }
|
||||
QString getAge() const { return getStringValue("Age"); }
|
||||
QString getVendor() const { return getStringValue("Vendor"); }
|
||||
QString getLanguage() const { return getStringValue("Language"); }
|
||||
QString getVersion() const { return getStringValue("Version"); }
|
||||
QLocale getLocale() const;
|
||||
|
||||
QString getStringValue(QString key) const;
|
||||
ISpVoice* getVoice() const { return m_voice; }
|
||||
|
||||
private:
|
||||
std::map<QString, QString> m_properties;
|
||||
ISpVoice* m_voice = nullptr;
|
||||
};
|
||||
|
||||
using PDFVoiceInfoList = std::vector<PDFVoiceInfo>;
|
||||
|
||||
class PDFToolAudioBook : public PDFToolAbstractApplication
|
||||
{
|
||||
public:
|
||||
virtual QString getStandardString(StandardString standardString) const override;
|
||||
virtual int execute(const PDFToolOptions& options) override;
|
||||
virtual Options getOptionsFlags() const override;
|
||||
|
||||
private:
|
||||
int fillVoices(const PDFToolOptions& options, PDFVoiceInfoList& list, bool fillVoicePointers);
|
||||
int showVoiceList(const PDFToolOptions& options);
|
||||
};
|
||||
|
||||
} // namespace pdftool
|
||||
|
||||
#endif
|
||||
|
||||
#endif // PDFTOOLAUDIOBOOK_H
|
Loading…
Reference in New Issue