// 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 . #ifndef PDFMULTIMEDIA_H #define PDFMULTIMEDIA_H #include "pdfobject.h" #include "pdffile.h" #include #include #include namespace pdf { class PDFDocument; struct PDFMediaMultiLanguageTexts { static PDFMediaMultiLanguageTexts parse(const PDFDocument* document, PDFObject object); std::map 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 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(m_data) ? &std::get(m_data) : nullptr; } const FrameData* getFrameData() const { return std::holds_alternative(m_data) ? &std::get(m_data) : nullptr; } const MarkerData* getMarkerData() const { return std::holds_alternative(m_data) ? &std::get(m_data) : nullptr; } private: Type m_type; std::variant m_data; }; class PDFMediaSoftwareIdentifier { public: explicit inline PDFMediaSoftwareIdentifier(QByteArray&& software, std::vector&& lowVersion, std::vector&& highVersion, bool lowVersionInclusive, bool highVersionInclusive, std::vector&& 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& getLowVersion() const { return m_lowVersion; } const std::vector& getHighVersion() const { return m_highVersion; } bool isLowVersionInclusive() const { return m_lowVersionInclusive; } bool isHighVersionInclusive() const { return m_highVersionInclusive; } const std::vector& getLanguages() const { return m_languages; } private: QByteArray m_software; std::vector m_lowVersion; std::vector m_highVersion; bool m_lowVersionInclusive; bool m_highVersionInclusive; std::vector 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&& playersMustUsed, std::vector&& playersAlternate, std::vector&& playersNeverUsed) : m_playersMustUsed(qMove(playersMustUsed)), m_playersNeverUsed(qMove(playersNeverUsed)), m_playersAlternate(qMove(playersAlternate)) { } static PDFMediaPlayers parse(const PDFDocument* document, PDFObject object); const std::vector& getPlayersMustUsed() const { return m_playersMustUsed; } const std::vector& getPlayersAlternate() const { return m_playersAlternate; } const std::vector& getPlayersNeverUsed() const { return m_playersNeverUsed; } private: std::vector m_playersMustUsed; std::vector m_playersAlternate; std::vector 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&& 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& getClipSections() const { return m_sections; } private: MediaClipData m_mediaClipData; std::vector 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& 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& getLanguages() const { return m_languages.value(); } private: std::optional m_audioDescriptions; std::optional m_textCaptions; std::optional m_audioOverdubs; std::optional m_subtitles; std::optional m_bitrate; std::optional m_minimumBitDepth; std::optional m_minimumScreenSize; std::optional> m_viewers; std::optional m_minimumPdfVersion; std::optional m_maximumPdfVersion; std::optional> 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(m_data) ? &std::get(m_data) : nullptr; } const SelectorRenditionData* getSelectorRenditionData() const { return std::holds_alternative(m_data) ? &std::get(m_data) : nullptr; } private: Type m_type = Type::Invalid; QString m_name; PDFMediaCriteria m_mustHonored; PDFMediaCriteria m_bestEffort; std::variant 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