PDF4QT/PdfForQtLib/sources/pdfmultimedia.h

538 lines
17 KiB
C++

// Copyright (C) 2019-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 PDFMULTIMEDIA_H
#define PDFMULTIMEDIA_H
#include "pdfobject.h"
#include "pdffile.h"
#include <QColor>
#include <map>
#include <optional>
namespace pdf
{
class PDFDocument;
struct PDFMediaMultiLanguageTexts
{
static PDFMediaMultiLanguageTexts parse(const PDFDocument* document, PDFObject object);
std::map<QByteArray, QString> texts;
};
class PDFMediaOffset
{
public:
enum class Type
{
Invalid,
Time,
Frame,
Marker
};
struct TimeData
{
PDFInteger seconds = 0;
};
struct FrameData
{
PDFInteger frame = 0;
};
struct MarkerData
{
QString namedOffset;
};
explicit inline PDFMediaOffset() :
m_type(Type::Invalid)
{
}
template<typename Data>
explicit inline PDFMediaOffset(Type type, Data&& data) :
m_type(type),
m_data(qMove(data))
{
}
static PDFMediaOffset parse(const PDFDocument* document, PDFObject object);
const TimeData* getTimeData() const { return std::holds_alternative<TimeData>(m_data) ? &std::get<TimeData>(m_data) : nullptr; }
const FrameData* getFrameData() const { return std::holds_alternative<FrameData>(m_data) ? &std::get<FrameData>(m_data) : nullptr; }
const MarkerData* getMarkerData() const { return std::holds_alternative<MarkerData>(m_data) ? &std::get<MarkerData>(m_data) : nullptr; }
private:
Type m_type;
std::variant<std::monostate, TimeData, FrameData, MarkerData> m_data;
};
class PDFMediaSoftwareIdentifier
{
public:
explicit inline PDFMediaSoftwareIdentifier(QByteArray&& software, std::vector<PDFInteger>&& lowVersion, std::vector<PDFInteger>&& highVersion,
bool lowVersionInclusive, bool highVersionInclusive, std::vector<QByteArray>&& languages) :
m_software(qMove(software)),
m_lowVersion(qMove(lowVersion)),
m_highVersion(qMove(highVersion)),
m_lowVersionInclusive(lowVersionInclusive),
m_highVersionInclusive(highVersionInclusive),
m_languages(qMove(languages))
{
}
static PDFMediaSoftwareIdentifier parse(const PDFDocument* document, PDFObject object);
const QByteArray& getSoftware() const { return m_software; }
const std::vector<PDFInteger>& getLowVersion() const { return m_lowVersion; }
const std::vector<PDFInteger>& getHighVersion() const { return m_highVersion; }
bool isLowVersionInclusive() const { return m_lowVersionInclusive; }
bool isHighVersionInclusive() const { return m_highVersionInclusive; }
const std::vector<QByteArray>& getLanguages() const { return m_languages; }
private:
QByteArray m_software;
std::vector<PDFInteger> m_lowVersion;
std::vector<PDFInteger> m_highVersion;
bool m_lowVersionInclusive;
bool m_highVersionInclusive;
std::vector<QByteArray> m_languages;
};
class PDFMediaPlayer
{
public:
explicit inline PDFMediaPlayer(PDFMediaSoftwareIdentifier&& softwareIdentifier) :
m_softwareIdentifier(qMove(softwareIdentifier))
{
}
static PDFMediaPlayer parse(const PDFDocument* document, PDFObject object);
const PDFMediaSoftwareIdentifier* getSoftwareIdentifier() const { return &m_softwareIdentifier; }
private:
PDFMediaSoftwareIdentifier m_softwareIdentifier;
};
class PDFMediaPlayers
{
public:
explicit inline PDFMediaPlayers() = default;
explicit inline PDFMediaPlayers(std::vector<PDFMediaPlayer>&& playersMustUsed,
std::vector<PDFMediaPlayer>&& playersAlternate,
std::vector<PDFMediaPlayer>&& playersNeverUsed) :
m_playersMustUsed(qMove(playersMustUsed)),
m_playersNeverUsed(qMove(playersNeverUsed)),
m_playersAlternate(qMove(playersAlternate))
{
}
static PDFMediaPlayers parse(const PDFDocument* document, PDFObject object);
const std::vector<PDFMediaPlayer>& getPlayersMustUsed() const { return m_playersMustUsed; }
const std::vector<PDFMediaPlayer>& getPlayersAlternate() const { return m_playersAlternate; }
const std::vector<PDFMediaPlayer>& getPlayersNeverUsed() const { return m_playersNeverUsed; }
private:
std::vector<PDFMediaPlayer> m_playersMustUsed;
std::vector<PDFMediaPlayer> m_playersAlternate;
std::vector<PDFMediaPlayer> m_playersNeverUsed;
};
class PDFMediaPermissions
{
public:
/// Are we allowed to save temporary file to play rendition?
enum class Permission
{
Never,
Extract,
Access,
Always
};
explicit inline PDFMediaPermissions() :
m_permission(Permission::Never)
{
}
explicit inline PDFMediaPermissions(Permission permission) :
m_permission(permission)
{
}
static PDFMediaPermissions parse(const PDFDocument* document, PDFObject object);
Permission getPermission() const { return m_permission; }
private:
Permission m_permission;
};
class PDFMediaPlayParameters
{
public:
explicit inline PDFMediaPlayParameters() = default;
enum class FitMode
{
Meet,
Slice,
Fill,
Scroll,
Hidden,
Default
};
enum class Duration
{
Intrinsic,
Infinity,
Seconds
};
struct PlayParameters
{
PDFInteger volume = 100;
bool controllerUserInterface = false;
FitMode fitMode = FitMode::Default;
bool playAutomatically = true;
PDFReal repeat = 1.0;
Duration duration = Duration::Intrinsic;
PDFReal durationSeconds = 0.0;
};
static PDFMediaPlayParameters parse(const PDFDocument* document, PDFObject object);
const PDFMediaPlayers* getPlayers() const { return &m_players; }
const PlayParameters* getPlayParametersMustHonored() const { return &m_mustHonored; }
const PlayParameters* getPlayParametersBestEffort() const { return &m_bestEffort; }
private:
PDFMediaPlayers m_players;
PlayParameters m_mustHonored;
PlayParameters m_bestEffort;
};
class PDFMediaScreenParameters
{
public:
enum class WindowType
{
Floating,
FullScreen,
Hidden,
ScreenAnnotation
};
enum class WindowRelativeTo
{
DocumentWindow,
ApplicationWindow,
VirtualDesktop,
Monitor
};
enum class OffscreenMode
{
NoAction,
MoveOnScreen,
NonViable
};
enum class ResizeMode
{
Fixed,
ResizableKeepAspectRatio,
Resizeble
};
struct ScreenParameters
{
WindowType windowType = WindowType::ScreenAnnotation;
QColor backgroundColor = QColor(Qt::white);
PDFReal opacity = 1.0;
PDFInteger monitorSpecification = 0;
QSize floatingWindowSize;
WindowRelativeTo floatingWindowReference = WindowRelativeTo::DocumentWindow;
Qt::Alignment floatingWindowAlignment = Qt::AlignCenter;
OffscreenMode floatingWindowOffscreenMode = OffscreenMode::MoveOnScreen;
bool floatingWindowHasTitleBar = true;
bool floatingWindowCloseable = true;
ResizeMode floatingWindowResizeMode = ResizeMode::Fixed;
PDFMediaMultiLanguageTexts floatingWindowTitle;
};
explicit inline PDFMediaScreenParameters() = default;
explicit inline PDFMediaScreenParameters(ScreenParameters&& mustHonored, ScreenParameters&& bestEffort) :
m_mustHonored(qMove(mustHonored)),
m_bestEffort(qMove(bestEffort))
{
}
static PDFMediaScreenParameters parse(const PDFDocument* document, PDFObject object);
const ScreenParameters* getScreenParametersMustHonored() const { return &m_mustHonored; }
const ScreenParameters* getScreenParametersBestEffort() const { return &m_bestEffort; }
private:
ScreenParameters m_mustHonored;
ScreenParameters m_bestEffort;
};
class PDFMediaClip
{
public:
struct MediaClipData
{
QString name;
PDFFileSpecification fileSpecification;
PDFObject dataStream;
QByteArray contentType;
PDFMediaPermissions permissions;
PDFMediaMultiLanguageTexts alternateTextDescriptions;
PDFMediaPlayers players;
QByteArray m_baseUrlMustHonored;
QByteArray m_baseUrlBestEffort;
};
struct MediaSectionBeginEnd
{
PDFMediaOffset offsetBegin;
PDFMediaOffset offsetEnd;
};
struct MediaSectionData
{
QString name;
PDFMediaMultiLanguageTexts alternateTextDescriptions;
MediaSectionBeginEnd m_mustHonored;
MediaSectionBeginEnd m_bestEffort;
};
explicit inline PDFMediaClip() = default;
explicit inline PDFMediaClip(MediaClipData&& mediaClipData, std::vector<MediaSectionData>&& sections) :
m_mediaClipData(qMove(mediaClipData)),
m_sections(qMove(sections))
{
}
static PDFMediaClip parse(const PDFDocument* document, PDFObject object);
const MediaClipData& getMediaClipData() const { return m_mediaClipData; }
const std::vector<MediaSectionData>& getClipSections() const { return m_sections; }
private:
MediaClipData m_mediaClipData;
std::vector<MediaSectionData> m_sections;
};
class PDFMediaMinimumBitDepth
{
public:
explicit inline PDFMediaMinimumBitDepth(PDFInteger screenMinimumBitDepth, PDFInteger monitorSpecifier) :
m_screenMinimumBitDepth(screenMinimumBitDepth),
m_monitorSpecifier(monitorSpecifier)
{
}
static PDFMediaMinimumBitDepth parse(const PDFDocument* document, PDFObject object);
PDFInteger getScreenMinimumBitDepth() const { return m_screenMinimumBitDepth; }
PDFInteger getMonitorSpecifier() const { return m_monitorSpecifier; }
private:
PDFInteger m_screenMinimumBitDepth;
PDFInteger m_monitorSpecifier;
};
class PDFMediaMinimumScreenSize
{
public:
explicit inline PDFMediaMinimumScreenSize(PDFInteger minimumWidth, PDFInteger minimumHeight, PDFInteger monitorSpecifier) :
m_minimumWidth(minimumWidth),
m_minimumHeight(minimumHeight),
m_monitorSpecifier(monitorSpecifier)
{
}
static PDFMediaMinimumScreenSize parse(const PDFDocument* document, PDFObject object);
private:
PDFInteger m_minimumWidth;
PDFInteger m_minimumHeight;
PDFInteger m_monitorSpecifier;
};
/// Media critera object (see PDF 1.7 reference, chapter 9.1.2). Some values are optional,
/// so they are implemented using std::optional. Always call "has" functions before
/// accessing the getters.
class PDFMediaCriteria
{
public:
explicit inline PDFMediaCriteria() = default;
static PDFMediaCriteria parse(const PDFDocument* document, PDFObject object);
bool hasAudioDescriptions() const { return m_audioDescriptions.has_value(); }
bool hasTextCaptions() const { return m_textCaptions.has_value(); }
bool hasAudioOverdubs() const { return m_audioOverdubs.has_value(); }
bool hasSubtitles() const { return m_subtitles.has_value(); }
bool hasBitrate() const { return m_bitrate.has_value(); }
bool hasMinimumBitDepth() const { return m_minimumBitDepth.has_value(); }
bool hasMinimumScreenSize() const { return m_minimumScreenSize.has_value(); }
bool hasViewers() const { return m_viewers.has_value(); }
bool hasMinimumPdfVersion() const { return m_minimumPdfVersion.has_value(); }
bool hasMaximumPdfVersion() const { return m_maximumPdfVersion.has_value(); }
bool hasLanguages() const { return m_languages.has_value(); }
bool getAudioDescriptions() const { return m_audioDescriptions.value(); }
bool getTextCaptions() const { return m_textCaptions.value(); }
bool getAudioOverdubs() const { return m_audioOverdubs.value(); }
bool getSubtitles() const { return m_subtitles.value(); }
PDFInteger getBitrate() const { return m_bitrate.value(); }
const PDFMediaMinimumBitDepth& getMinimumBitDepth() const { return m_minimumBitDepth.value(); }
const PDFMediaMinimumScreenSize& getMinimumScreenSize() const { return m_minimumScreenSize.value(); }
const std::vector<PDFMediaSoftwareIdentifier>& getViewers() const { return m_viewers.value(); }
const QByteArray& getMinimumPdfVersion() const { return m_minimumPdfVersion.value(); }
const QByteArray& getMaximumPdfVersion() const { return m_maximumPdfVersion.value(); }
const std::vector<QByteArray>& getLanguages() const { return m_languages.value(); }
private:
std::optional<bool> m_audioDescriptions;
std::optional<bool> m_textCaptions;
std::optional<bool> m_audioOverdubs;
std::optional<bool> m_subtitles;
std::optional<PDFInteger> m_bitrate;
std::optional<PDFMediaMinimumBitDepth> m_minimumBitDepth;
std::optional<PDFMediaMinimumScreenSize> m_minimumScreenSize;
std::optional<std::vector<PDFMediaSoftwareIdentifier>> m_viewers;
std::optional<QByteArray> m_minimumPdfVersion;
std::optional<QByteArray> m_maximumPdfVersion;
std::optional<std::vector<QByteArray>> m_languages;
};
/// Rendition object
class PDFRendition
{
public:
enum class Type
{
Invalid,
Media,
Selector
};
struct MediaRenditionData
{
PDFMediaClip clip;
PDFMediaPlayParameters playParameters;
PDFMediaScreenParameters screenParameters;
};
struct SelectorRenditionData
{
PDFObject renditions;
};
static PDFRendition parse(const PDFDocument* document, PDFObject object);
Type getType() const { return m_type; }
const QString& getName() const { return m_name; }
const PDFMediaCriteria* getMediaCriteriaMustHonored() const { return &m_mustHonored; }
const PDFMediaCriteria* getMediaCriteriaBestEffort() const { return &m_bestEffort; }
const MediaRenditionData* getMediaRenditionData() const { return std::holds_alternative<MediaRenditionData>(m_data) ? &std::get<MediaRenditionData>(m_data) : nullptr; }
const SelectorRenditionData* getSelectorRenditionData() const { return std::holds_alternative<SelectorRenditionData>(m_data) ? &std::get<SelectorRenditionData>(m_data) : nullptr; }
private:
Type m_type = Type::Invalid;
QString m_name;
PDFMediaCriteria m_mustHonored;
PDFMediaCriteria m_bestEffort;
std::variant<std::monostate, MediaRenditionData, SelectorRenditionData> m_data;
};
/// Sound object, see chapter 9.2 in PDF 1.7 reference
class PDFSound
{
public:
explicit inline PDFSound() = default;
enum class Format
{
Raw,
Signed,
muLaw,
ALaw
};
const PDFFileSpecification* getFileSpecification() const { return &m_fileSpecification; }
PDFReal getSamplingRate() const { return m_samplingRate; }
PDFInteger getChannels() const { return m_channels; }
PDFInteger getBitsPerSample() const { return m_bitsPerSample; }
Format getFormat() const { return m_format; }
const QByteArray& getSoundCompression() { return m_soundCompression; }
const PDFObject& getSoundCompressionParameters() const { return m_soundCompressionParameters; }
const PDFStream* getStream() const { return m_streamObject.isStream() ? m_streamObject.getStream() : nullptr; }
/// If this function returns true, sound is valid
bool isValid() const { return getStream(); }
/// Creates a new sound from the object. If data are invalid, then invalid object
/// is returned, no exception is thrown.
static PDFSound parse(const PDFDocument* document, PDFObject object);
private:
PDFFileSpecification m_fileSpecification;
PDFReal m_samplingRate = 0.0;
PDFInteger m_channels = 0;
PDFInteger m_bitsPerSample = 0;
Format m_format = Format::Raw;
QByteArray m_soundCompression;
PDFObject m_soundCompressionParameters;
PDFObject m_streamObject;
};
} // namespace pdf
#endif // PDFMULTIMEDIA_H