// 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 #include #include namespace pdf { class PDFObjectStorage; using PDFPoint3D = std::array; struct PDFMediaMultiLanguageTexts { static PDFMediaMultiLanguageTexts parse(const PDFObjectStorage* storage, 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 PDFObjectStorage* storage, 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 PDFObjectStorage* storage, 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 PDFObjectStorage* storage, 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 PDFObjectStorage* storage, 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 PDFObjectStorage* storage, 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 PDFObjectStorage* storage, 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 PDFObjectStorage* storage, 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 PDFObjectStorage* storage, 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 PDFObjectStorage* storage, 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 PDFObjectStorage* storage, 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 PDFObjectStorage* storage, 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 PDFObjectStorage* storage, 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 PDFObjectStorage* storage, 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; }; /// Movie object, see chapter 9.3 in PDF 1.7 reference class PDFMovie { public: explicit inline PDFMovie() = default; const PDFFileSpecification* getMovieFileSpecification() const { return &m_movieFile; } QSize getWindowSize() const { return m_windowSize; } PDFInteger getRotationAngle() const { return m_rotationAngle; } bool isPosterVisible() const { return m_showPoster; } const PDFObject& getPosterObject() const { return m_poster; } /// Creates a new movie from the object. If data are invalid, then invalid object /// is returned, no exception is thrown. static PDFMovie parse(const PDFObjectStorage* storage, PDFObject object); private: PDFFileSpecification m_movieFile; QSize m_windowSize; PDFInteger m_rotationAngle = 0; bool m_showPoster = false; PDFObject m_poster; }; /// Movie activation object, see table 9.31 in PDF 1.7 reference class PDFMovieActivation { public: explicit inline PDFMovieActivation() = default; struct MovieTime { PDFInteger value = 0; std::optional unitsPerSecond; }; enum class Mode { Once, Open, Repeat, Palindrome }; MovieTime getStartTime() const { return m_start; } MovieTime getDuration() const { return m_duration; } PDFReal getRate() const { return m_rate; } PDFReal getVolume() const { return m_volume; } bool isShowControls() const { return m_showControls; } bool isSynchronous() const { return m_synchronous; } Mode getMode() const { return m_mode; } bool hasScale() const { return m_scaleDenominator != 0; } PDFInteger getScaleNumerator() const { return m_scaleNumerator; } PDFInteger getScaleDenominator() const { return m_scaleDenominator; } QPointF getRelativeWindowPosition() const { return m_relativeWindowPosition; } /// Creates a new movie from the object. If data are invalid, then invalid object /// is returned, no exception is thrown. static PDFMovieActivation parse(const PDFObjectStorage* storage, PDFObject object); private: static MovieTime parseMovieTime(const PDFObjectStorage* storage, PDFObject object); static PDFInteger parseMovieTimeFromString(const QByteArray& string); MovieTime m_start; MovieTime m_duration; PDFReal m_rate = 1.0; PDFReal m_volume = 1.0; bool m_showControls = false; bool m_synchronous = false; Mode m_mode = Mode::Once; PDFInteger m_scaleNumerator = 0; PDFInteger m_scaleDenominator = 0; QPointF m_relativeWindowPosition; }; /// Rich media position of window class PDFRichMediaWindowPosition { public: explicit inline PDFRichMediaWindowPosition() = default; enum class Alignment { Near, Center, Far }; Alignment getHorizontalAlignment() const { return m_horizontalAlignment; } Alignment getVerticalAlignment() const { return m_verticalAlignment; } PDFReal getHorizontalOffset() const { return m_horizontalOffset; } PDFReal getVerticalOffset() const { return m_verticalOffset; } /// Creates a new rich media position from the object. If data are invalid, then invalid object /// is returned, no exception is thrown. static PDFRichMediaWindowPosition parse(const PDFObjectStorage* storage, PDFObject object); private: Alignment m_horizontalAlignment = Alignment::Far; Alignment m_verticalAlignment = Alignment::Near; PDFReal m_horizontalOffset = 18.0; PDFReal m_verticalOffset = 18.0; }; /// Rich media window class PDFRichMediaWindow { public: explicit inline PDFRichMediaWindow() = default; enum SizeHintType { Default, Max, Min, End }; PDFReal getWidth(SizeHintType type) const { return m_width.at(type); } PDFReal getHeight(SizeHintType type) const { return m_height.at(type); } const PDFRichMediaWindowPosition& getRichMediaWindowPosition() const { return m_richMediaPosition; } using WindowSize = std::array; /// Creates a new rich media window from the object. If data are invalid, then invalid object /// is returned, no exception is thrown. static PDFRichMediaWindow parse(const PDFObjectStorage* storage, PDFObject object); private: WindowSize m_width = { 288.0, 576.0, 72.0 }; WindowSize m_height = { 288.0, 576.0, 72.0 }; PDFRichMediaWindowPosition m_richMediaPosition; }; /// Rich media presentation defines, how rich media will appear on the page, /// or if it should be launched in a new window. class PDFRichMediaPresentation { public: explicit inline PDFRichMediaPresentation() = default; enum class Style { Embedded, Windowed }; Style getStyle() const { return m_style; } const PDFRichMediaWindow& getWindow() const { return m_window; } bool isTransparent() const { return m_isTransparent; } bool isNavigationPaneEnabled() const { return m_isNavigationPaneEnabled; } bool isToolbarEnabled() const { return m_isToolbarEnabled; } bool isContentClickPassed() const { return m_isContentClickPassed; } /// Creates a new rich media presentation from the object. If data are invalid, then invalid object /// is returned, no exception is thrown. static PDFRichMediaPresentation parse(const PDFObjectStorage* storage, PDFObject object); private: Style m_style = Style::Embedded; PDFRichMediaWindow m_window; ///< Meaningful only when style is windowed bool m_isTransparent = false; bool m_isNavigationPaneEnabled = false; bool m_isToolbarEnabled = false; bool m_isContentClickPassed = false; }; /// Rich media animation class PDFRichMediaAnimation { public: explicit inline PDFRichMediaAnimation() = default; enum class Animation { None, Linear, Oscillating }; Animation getAnimation() const { return m_animation; } PDFInteger getPlayCount() const { return m_playCount; } PDFReal getSpeed() const { return m_speed; } /// Creates a new rich media animation from the object. If data are invalid, then invalid object /// is returned, no exception is thrown. static PDFRichMediaAnimation parse(const PDFObjectStorage* storage, PDFObject object); private: Animation m_animation = Animation::None; PDFInteger m_playCount = -1; PDFReal m_speed = 1; }; /// Rich media deactivation dictionary class PDFRichMediaDeactivation { public: explicit inline PDFRichMediaDeactivation() = default; enum class DeactivationMode { ExplicitlyByUserAction, PageLoseFocus, PageHide }; DeactivationMode getMode() const { return m_mode; } /// Creates a new rich media deactivation from the object. If data are invalid, then invalid object /// is returned, no exception is thrown. static PDFRichMediaDeactivation parse(const PDFObjectStorage* storage, PDFObject object); private: DeactivationMode m_mode = DeactivationMode::ExplicitlyByUserAction; }; /// Rich media activation dictionary class PDFRichMediaActivation { public: explicit inline PDFRichMediaActivation() = default; enum class ActivationMode { ExplicitlyByUserAction, PageEnterFocus, PageShow }; ActivationMode getActivationMode() const { return m_mode; } const PDFRichMediaAnimation& getAnimation() const { return m_animation; } PDFObjectReference getView() const { return m_view; } PDFObjectReference getConfiguration() const { return m_configuration; } const PDFRichMediaPresentation& getPresentation() const { return m_presentation; } /// Creates a new rich media activation from the object. If data are invalid, then invalid object /// is returned, no exception is thrown. static PDFRichMediaActivation parse(const PDFObjectStorage* storage, PDFObject object); private: ActivationMode m_mode = ActivationMode::ExplicitlyByUserAction; PDFRichMediaAnimation m_animation; PDFObjectReference m_view; PDFObjectReference m_configuration; PDFRichMediaPresentation m_presentation; }; /// Rich media settings class PDFRichMediaSettings { public: explicit inline PDFRichMediaSettings() = default; const PDFRichMediaActivation& getActivation() const { return m_activation; } const PDFRichMediaDeactivation& getDeactivation() const { return m_deactivation; } /// Creates a new rich media settings from the object. If data are invalid, then invalid object /// is returned, no exception is thrown. static PDFRichMediaSettings parse(const PDFObjectStorage* storage, PDFObject object); private: PDFRichMediaActivation m_activation; PDFRichMediaDeactivation m_deactivation; }; /// Rich media content dictionary class PDFRichMediaContent { public: explicit inline PDFRichMediaContent() = default; using Assets = std::map; using Configurations = std::vector; using Views = std::vector; const Assets& getAssets() const { return m_assets; } const Configurations& getConfigurations() const { return m_configurations; } const Views& getViews() const { return m_views; } /// Creates a new rich media content from the object. If data are invalid, then invalid object /// is returned, no exception is thrown. static PDFRichMediaContent parse(const PDFObjectStorage* storage, PDFObject object); private: Assets m_assets; Configurations m_configurations; Views m_views; }; enum class RichMediaType { Unspecified, _3D, Sound, Flash, Video }; /// Rich media configuration dictionary class PDFRichMediaConfiguration { public: explicit inline PDFRichMediaConfiguration() = default; using Instances = std::vector; RichMediaType getType() const { return m_type; } const Instances& getInstances() const { return m_instances; } /// Creates a new rich media configuration from the object. If data are invalid, then invalid object /// is returned, no exception is thrown. static PDFRichMediaConfiguration parse(const PDFObjectStorage* storage, PDFObject object); private: RichMediaType m_type = RichMediaType::Unspecified; Instances m_instances; }; /// Rich media instance dictionary class PDFRichMediaInstance { public: explicit inline PDFRichMediaInstance() = default; RichMediaType getType() const { return m_type; } PDFObjectReference getAsset() const { return m_asset; } /// Creates a new rich media instance from the object. If data are invalid, then invalid object /// is returned, no exception is thrown. static PDFRichMediaInstance parse(const PDFObjectStorage* storage, PDFObject object); private: RichMediaType m_type = RichMediaType::Unspecified; PDFObjectReference m_asset; }; /// 3D PDF activation dictionary class PDF3DActivation { public: /// Activation/deactivation mode enum class TriggerMode { ExplicitlyByUserAction, ///< Explicitly turned on/off by user PageFocus, ///< Turned on/off by gain/lose focus PageVisibility ///< Turned on/off by page shown/hidden }; /// Activation mode enum class ActivationMode { Uninstantiated, Instantiated, Live }; /// Style enum class Style { Embedded, Windowed }; TriggerMode getActivationTriggerMode() const { return m_activationTriggerMode; } TriggerMode getDeactivationTriggerMode() const { return m_deactivationTriggerMode; } ActivationMode getActivationMode() const { return m_activationMode; } ActivationMode getDeactivationMode() const { return m_deactivationMode; } bool hasToolbar() const { return m_toolbar; } bool hasNavigator() const { return m_navigator; } Style getStyle() const { return m_style; } const PDFRichMediaWindow& getWindow() const { return m_window; } bool isTransparent() const { return m_transparent; } /// Creates a new 3D annotation activation from the object. If data are invalid, then invalid object /// is returned, no exception is thrown. static PDF3DActivation parse(const PDFObjectStorage* storage, PDFObject object); private: TriggerMode m_activationTriggerMode = TriggerMode::ExplicitlyByUserAction; TriggerMode m_deactivationTriggerMode = TriggerMode::PageVisibility; ActivationMode m_activationMode = ActivationMode::Live; ActivationMode m_deactivationMode = ActivationMode::Uninstantiated; bool m_toolbar = true; bool m_navigator = false; Style m_style = Style::Embedded; PDFRichMediaWindow m_window; bool m_transparent = false; }; /// 3D PDF render mode class PDF3DRenderMode { public: explicit inline PDF3DRenderMode() = default; enum class RenderMode { Solid, SolidWireframe, Transparent, TransparentWireframe, BoundingBox, TransparentBoundingBox, TransparentBoundingBoxOutline, Wireframe, ShadedWireframe, HiddenWireframe, Vertices, ShadedVertices, Illustration, SolidOutline, ShadedIllustration }; enum class FaceColorMode { BG, ///< Current background color Color ///< Color specified }; RenderMode getRenderMode() const { return m_renderMode; } QColor getAuxiliaryColor() const { return m_auxiliaryColor; } QColor getFaceColor() const { return m_faceColor; } FaceColorMode getFaceColorMode() const { return m_faceColorMode; } PDFReal getOpacity() const { return m_opacity; } PDFReal getCreaseAngle() const { return m_creaseAngle; } /// Creates a new 3D render mode from the object. If data are invalid, then invalid object /// is returned, no exception is thrown. static PDF3DRenderMode parse(const PDFObjectStorage* storage, PDFObject object); private: RenderMode m_renderMode = RenderMode::Solid; QColor m_auxiliaryColor = Qt::black; QColor m_faceColor = Qt::black; FaceColorMode m_faceColorMode = FaceColorMode::BG; PDFReal m_opacity = 0.5; PDFReal m_creaseAngle = 45.0; }; /// 3D PDF node (part of 3D structure) class PDF3DNode { public: explicit inline PDF3DNode() = default; const QString& getName() const { return m_name; } const std::optional& getOpacity() const { return m_opacity; } const std::optional& getVisibility() const { return m_visibility; } const std::optional& getMatrix() const { return m_matrix; } PDFObjectReference getInstance() const { return m_instance; } const QString& getData() const { return m_data; } const std::optional& getRenderMode() const { return m_renderMode; } /// Creates a new 3D node from the object. If data are invalid, then invalid object /// is returned, no exception is thrown. static PDF3DNode parse(const PDFObjectStorage* storage, PDFObject object); private: QString m_name; std::optional m_opacity; std::optional m_visibility; std::optional m_matrix; PDFObjectReference m_instance; QString m_data; std::optional m_renderMode; }; /// 3D PDF Cross section class PDF3DCrossSection { public: explicit inline PDF3DCrossSection() = default; enum class Direction { X, Y, Z }; PDFPoint3D getCenterOfRotation() const { return m_centerOfRotation; } PDFPoint3D getRotationAngles() const { return m_rotationAngles; } Direction getPerpendicularDirection() const { return m_perpendicularDirection; } PDFReal getCutPlaneOpacity() const { return m_cutPlaneOpacity; } QColor getCutPlaneColor() const { return m_cutPlaneColor; } bool getIntersectionVisibility() const { return m_intersectionVisibility; } QColor getIntersectionColor() const { return m_intersectionColor; } bool getShowTransparent() const { return m_showTransparent; } bool getSectionCapping() const { return m_sectionCapping; } /// Creates a new 3D cross section from the object. If data are invalid, then invalid object /// is returned, no exception is thrown. static PDF3DCrossSection parse(const PDFObjectStorage* storage, PDFObject object); private: PDFPoint3D m_centerOfRotation{}; PDFPoint3D m_rotationAngles{}; Direction m_perpendicularDirection = Direction::X; PDFReal m_cutPlaneOpacity = 0.5; QColor m_cutPlaneColor = Qt::white; bool m_intersectionVisibility = false; QColor m_intersectionColor = Qt::green; bool m_showTransparent = false; bool m_sectionCapping = false; }; /// 3D PDF lighting scheme class PDF3DLightingScheme { public: explicit inline PDF3DLightingScheme() = default; enum class LightingScheme { Artwork, None, White, Day, Night, Hard, Primary, Blue, Red, Cube, CAD, Headlamp }; LightingScheme getLightingScheme() const { return m_scheme; } /// Creates a new 3D lighting scheme from the object. If data are invalid, then invalid object /// is returned, no exception is thrown. static PDF3DLightingScheme parse(const PDFObjectStorage* storage, PDFObject object); private: LightingScheme m_scheme = LightingScheme::Artwork; }; /// 3D PDF background class PDF3DBackground { public: explicit inline PDF3DBackground() = default; QColor getColor() const { return m_color; } bool getEntireAnnotation() const { return m_entireAnnotation; } /// Creates a new 3D background from the object. If data are invalid, then invalid object /// is returned, no exception is thrown. static PDF3DBackground parse(const PDFObjectStorage* storage, PDFObject object); private: QColor m_color; bool m_entireAnnotation = false; }; /// 3D PDF projection class PDF3DProjection { public: explicit inline PDF3DProjection() = default; enum class Projection { Orthographic, Perspective }; enum class ClippingStyle { Explicit, Automatic }; enum class ScaleMode { W, H, Min, Max, Absolute, Value ///< This means projection scaling diameter is defined }; Projection getProjection() const { return m_projection; } ClippingStyle getClippingStyle() const { return m_clippingStyle; } PDFReal getNearPlane() const { return m_near; } PDFReal getFarPlane() const { return m_far; } PDFReal getFieldOfViewAngle() const { return m_fieldOfViewAngle; } PDFReal getProjectionScalingDiameter() const { return m_projectionScalingDiameter; } ScaleMode getProjectionScaleMode() const { return m_projectionScaleMode; } PDFReal getScaleFactor() const { return m_scaleFactor; } ScaleMode getScaleMode() const { return m_scaleMode; } /// Creates a new 3D projection from the object. If data are invalid, then invalid object /// is returned, no exception is thrown. static PDF3DProjection parse(const PDFObjectStorage* storage, PDFObject object); private: Projection m_projection = Projection::Perspective; ClippingStyle m_clippingStyle = ClippingStyle::Automatic; PDFReal m_near = 0.0; PDFReal m_far = qInf(); PDFReal m_fieldOfViewAngle = 90.0; PDFReal m_projectionScalingDiameter = 0.0; ScaleMode m_projectionScaleMode = ScaleMode::W; PDFReal m_scaleFactor = 1.0; ScaleMode m_scaleMode = ScaleMode::Absolute; }; /// 3D PDF view class PDF3DView { public: explicit inline PDF3DView() = default; enum class MatrixSelection { M, U3D }; const QString& getExternalName() const { return m_externalName; } const QString& getInternalName() const { return m_internalName; } MatrixSelection getMatrixSelection() const{ return m_matrixSelection; } const QMatrix4x4& getCameraToWorld() const { return m_cameraToWorld; } const QStringList& getU3DPath() const { return m_U3Dpath; } PDFReal getCameraDistance() const { return m_cameraDistance; } const PDF3DProjection& getProjection() const { return m_projection; } const PDFObject& getOverlay() const { return m_overlay; } const PDF3DBackground& getBackground() const { return m_background; } const PDF3DRenderMode& getRenderMode() const { return m_renderMode; } const PDF3DLightingScheme& getLightingScheme() const { return m_lightingScheme; } const std::vector& getCrossSections() const { return m_crossSections; } const std::vector& getNodes() const { return m_nodes; } bool getNodesRestore() const { return m_nodesRestore; } /// Creates a new 3D view from the object. If data are invalid, then invalid object /// is returned, no exception is thrown. static PDF3DView parse(const PDFObjectStorage* storage, PDFObject object); private: QString m_externalName; QString m_internalName; MatrixSelection m_matrixSelection = MatrixSelection::M; QMatrix4x4 m_cameraToWorld; QStringList m_U3Dpath; PDFReal m_cameraDistance = 0.0; PDF3DProjection m_projection; PDFObject m_overlay; PDF3DBackground m_background; PDF3DRenderMode m_renderMode; PDF3DLightingScheme m_lightingScheme; std::vector m_crossSections; std::vector m_nodes; bool m_nodesRestore = false; }; /// 3D PDF animation class PDF3DAnimation { public: explicit inline PDF3DAnimation() = default; enum class Animation { None, Linear, Oscillating }; Animation getAnimation() const { return m_animation; } PDFInteger getPlayCount() const { return m_playCount; } PDFReal getSpeed() const { return m_speed; } /// Creates a new 3D animation from the object. If data are invalid, then invalid object /// is returned, no exception is thrown. static PDF3DAnimation parse(const PDFObjectStorage* storage, PDFObject object); private: Animation m_animation = Animation::None; PDFInteger m_playCount = -1; PDFReal m_speed = 1; }; /// 3D PDF stream class PDF3DStream { public: explicit inline PDF3DStream() = default; enum class Type { Invalid, U3D, PRC }; PDFObject getStream() const { return m_stream; } Type getType() const { return m_type; } const std::vector& getViews() const { return m_views; } const std::optional& getDefaultView() const { return m_defaultView; } PDFObject getResources() const { return m_resources; } PDFObject getOnInstantiateJavascript() const { return m_onInstantiateJavascript; } PDF3DAnimation getAnimation() const { return m_animation; } PDFObject getColorSpace() const { return m_colorSpace; } /// Creates a new 3D stream from the object. If data are invalid, then invalid object /// is returned, no exception is thrown. static PDF3DStream parse(const PDFObjectStorage* storage, PDFObject object); private: PDFObject m_stream; Type m_type = Type::Invalid; std::vector m_views; std::optional m_defaultView; PDFObject m_resources; PDFObject m_onInstantiateJavascript; PDF3DAnimation m_animation; PDFObject m_colorSpace; }; } // namespace pdf #endif // PDFMULTIMEDIA_H