pdf_writer/renditions.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
use super::*;
/// Writer for an _rendition dictionary_.
///
/// This struct is created by [`Action::rendition`].
pub struct Rendition<'a> {
dict: Dict<'a>,
}
writer!(Rendition: |obj| {
let mut dict = obj.dict();
dict.pair(Name(b"Type"), Name(b"Rendition"));
Self { dict }
});
impl<'a> Rendition<'a> {
/// Write the `/S` attribute to set the rendition type.
pub fn subtype(&mut self, kind: RenditionType) -> &mut Self {
self.pair(Name(b"S"), kind.to_name());
self
}
/// Write the `/N` attribute. Specify the name of the rendition for use in a
/// user interface and for name tree lookup by JavaScript actions.
pub fn name(&mut self, text: TextStr) -> &mut Self {
self.pair(Name(b"N"), text);
self
}
/// Start writing the `/C`, i.e. media clip, dictionary which specifies what
/// media should be played. Only permissible for Media Renditions.
pub fn media_clip(&mut self) -> MediaClip<'_> {
self.insert(Name(b"C")).start()
}
/// Start writing the `/P`, i.e. media play parameters, dictionary which
/// specifies how the media should be played. Only permissible for Media
/// Renditions.
pub fn media_play_params(&mut self) -> MediaPlayParams<'_> {
self.insert(Name(b"P")).start()
}
}
deref!('a, Rendition<'a> => Dict<'a>, dict);
/// Writer for an _media clip dictionary_.
///
/// This struct is created by [`Rendition::media_clip`].
///
/// ## Note on reader compatibility
///
/// Different PDF readers may have support for different media codecs and
/// container formats.
///
/// For example, [Adobe's documentation][1] states that Adobe Acrobat can play
/// videos in MP4, MOV, M4V, 3GP, and 3G2 containers using the H.264 codec.
///
/// Other readers may depend on the media libraries installed on the system. KDE
/// Okular, for example, uses the Phonon library to support a range of media
/// formats.
///
/// Yet other viewers do not support media clips at all. At the time of writing,
/// this includes the popular Pdfium library used by Google Chrome and Microsoft
/// Edge, `pdf.js` used by Firefox, mupdf, and Quartz, the PDF viewer on Apple
/// platforms.
///
/// [1]: https://helpx.adobe.com/acrobat/using/playing-video-audio-multimedia-formats.html#supported_video_audio_and_interactive_formats
pub struct MediaClip<'a> {
dict: Dict<'a>,
}
writer!(MediaClip: |obj| {
let mut dict = obj.dict();
dict.pair(Name(b"Type"), Name(b"MediaClip"));
Self { dict }
});
impl<'a> MediaClip<'a> {
/// Write the `/S` attribute to set the media clip type.
pub fn subtype(&mut self, kind: MediaClipType) -> &mut Self {
self.pair(Name(b"S"), kind.to_name());
self
}
/// Write the `/N` attribute. Specifies the name of the media clip, for use
/// in the user interface.
pub fn name(&mut self, text: TextStr) -> &mut Self {
self.pair(Name(b"N"), text);
self
}
/// Start writing the `/D` dictionary specifying the media data.
pub fn data(&mut self) -> FileSpec<'_> {
self.insert(Name(b"D")).start()
}
/// Write the `/CT` attribute identifying the type of data in `/D`, i.e. the
/// MIME type.
pub fn data_type(&mut self, tf: Str) -> &mut Self {
self.pair(Name(b"CT"), tf);
self
}
/// Start writing the `/P`, i.e. media permissions, dictionary.
pub fn permissions(&mut self) -> MediaPermissions<'_> {
self.insert(Name(b"P")).start()
}
/// Write the `/Alt` attribute, listing alternate text descriptions which
/// are specified as a multi-language text array. A multi-language text
/// array shall contain pairs of strings.
pub fn alt_texts<'b>(
&mut self,
texts: impl IntoIterator<Item = TextStr<'b>>,
) -> &mut Self {
self.insert(Name(b"Alt")).array().items(texts);
self
}
}
deref!('a, MediaClip<'a> => Dict<'a>, dict);
/// Writer for an _media play parameters dictionary_.
///
/// This struct is created by [`Rendition::media_play_params`].
pub struct MediaPlayParams<'a> {
dict: Dict<'a>,
}
writer!(MediaPlayParams: |obj| {
let mut dict = obj.dict();
dict.pair(Name(b"Type"), Name(b"MediaPlayParams"));
Self { dict }
});
impl<'a> MediaPlayParams<'a> {
/// Write the `/C` attribute inside a `/BE` dictionary specifying whether to
/// display a player-specific controls.
///
/// This avoids implementing the "must honour" (MH) or "best effort" (BE)
/// dictionaries for MediaPlayParams, as the required boiler-plate code
/// would be high, and its usefulness low.
pub fn controls(&mut self, c: bool) -> &mut Self {
self.insert(Name(b"BE")).dict().pair(Name(b"C"), c);
self
}
}
deref!('a, MediaPlayParams<'a> => Dict<'a>, dict);
/// Writer for an _media permissions dictionary_.
///
/// This struct is created by [`MediaClip::permissions`].
pub struct MediaPermissions<'a> {
dict: Dict<'a>,
}
writer!(MediaPermissions: |obj| {
let mut dict = obj.dict();
dict.pair(Name(b"Type"), Name(b"MediaPermissions"));
Self { dict }
});
impl<'a> MediaPermissions<'a> {
/// Write the `/TF` attribute to control permissions to write a temporary file.
pub fn temp_file(&mut self, tf: TempFileType) -> &mut Self {
self.pair(Name(b"TF"), tf.to_str());
self
}
}
deref!('a, MediaPermissions<'a> => Dict<'a>, dict);
/// The circumstances under which it is acceptable to write a temporary file in
/// order to play a media clip.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum TempFileType {
/// Never allowed.
Never,
/// Allowed only if the document permissions allow content extraction.
Extract,
/// Allowed only if the document permissions allow content extraction,
/// including for accessibility purposes.
Access,
/// Always allowed.
Always,
}
impl TempFileType {
pub(crate) fn to_str(self) -> Str<'static> {
match self {
Self::Never => Str(b"TEMPNEVER"),
Self::Extract => Str(b"TEMPEXTRACT"),
Self::Access => Str(b"TEMPACCESS"),
Self::Always => Str(b"TEMPALWAYS"),
}
}
}
/// Type of rendition objects.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum RenditionType {
/// Media Rendition.
Media,
/// Selector Rendition.
Selector,
}
impl RenditionType {
pub(crate) fn to_name(self) -> Name<'static> {
match self {
Self::Media => Name(b"MR"),
Self::Selector => Name(b"SR"),
}
}
}
/// Type of media clip objects.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum MediaClipType {
/// Media Clip Data.
Data,
/// Media Clip Section.
Section,
}
impl MediaClipType {
pub(crate) fn to_name(self) -> Name<'static> {
match self {
Self::Data => Name(b"MCD"),
Self::Section => Name(b"MCS"),
}
}
}