@@ -1116,22 +1116,21 @@ pub enum StructRole2 {
11161116 Strong ,
11171117 /// A link.
11181118 Link ,
1119- /// An association between an annotation and the content it belongs to. PDF
1120- /// 1.5+
1119+ /// An association between an annotation and the content it belongs to.
11211120 Annot ,
11221121 /// Form widget.
11231122 Form ,
1124- /// Ruby annotation for CJK text. PDF 1.5+
1123+ /// Ruby annotation for CJK text.
11251124 Ruby ,
1126- /// Base text of a Ruby annotation. PDF 1.5+
1125+ /// Base text of a Ruby annotation.
11271126 RB ,
1128- /// Annotation text of a Ruby annotation. PDF 1.5+
1127+ /// Annotation text of a Ruby annotation.
11291128 RT ,
1130- /// Warichu annotation for CJK text. PDF 1.5+
1129+ /// Warichu annotation for CJK text.
11311130 Warichu ,
1132- /// Text of a Warichu annotation. PDF 1.5+
1131+ /// Text of a Warichu annotation.
11331132 WT ,
1134- /// Punctuation of a Warichu annotation. PDF 1.5+
1133+ /// Punctuation of a Warichu annotation.
11351134 WP ,
11361135 /// A list.
11371136 L ,
@@ -1214,125 +1213,88 @@ impl StructRole2 {
12141213 }
12151214 }
12161215
1217- /// Return the corresponding PDF 1.7 [`StructRole`] for this role or `None`.
1218- pub fn into_pdf_1_7 ( self ) -> Option < StructRole > {
1219- match self {
1220- Self :: Document => Some ( StructRole :: Document ) ,
1221- Self :: DocumentFragment => None ,
1222- Self :: Part => Some ( StructRole :: Part ) ,
1223- Self :: Sect => Some ( StructRole :: Sect ) ,
1224- Self :: Div => Some ( StructRole :: Div ) ,
1225- Self :: Aside => None ,
1226- Self :: NonStruct => Some ( StructRole :: NonStruct ) ,
1227- Self :: P => Some ( StructRole :: P ) ,
1228- Self :: Heading ( n) if n. get ( ) == 1 => Some ( StructRole :: H1 ) ,
1229- Self :: Heading ( n) if n. get ( ) == 2 => Some ( StructRole :: H2 ) ,
1230- Self :: Heading ( n) if n. get ( ) == 3 => Some ( StructRole :: H3 ) ,
1231- Self :: Heading ( n) if n. get ( ) == 4 => Some ( StructRole :: H4 ) ,
1232- Self :: Heading ( n) if n. get ( ) == 5 => Some ( StructRole :: H5 ) ,
1233- Self :: Heading ( n) if n. get ( ) == 6 => Some ( StructRole :: H6 ) ,
1234- Self :: Heading ( _) => None ,
1235- Self :: StructuredHeading => None ,
1236- Self :: Title => None ,
1237- Self :: FENote => None ,
1238- Self :: Sub => None ,
1239- Self :: Lbl => Some ( StructRole :: Lbl ) ,
1240- Self :: Span => Some ( StructRole :: Span ) ,
1241- Self :: Em => None ,
1242- Self :: Strong => None ,
1243- Self :: Link => Some ( StructRole :: Link ) ,
1244- Self :: Annot => Some ( StructRole :: Annot ) ,
1245- Self :: Form => Some ( StructRole :: Form ) ,
1246- Self :: Ruby => Some ( StructRole :: Ruby ) ,
1247- Self :: RB => Some ( StructRole :: RB ) ,
1248- Self :: RT => Some ( StructRole :: RT ) ,
1249- Self :: Warichu => Some ( StructRole :: Warichu ) ,
1250- Self :: WT => Some ( StructRole :: WT ) ,
1251- Self :: WP => Some ( StructRole :: WP ) ,
1252- Self :: L => Some ( StructRole :: L ) ,
1253- Self :: LI => Some ( StructRole :: LI ) ,
1254- Self :: LBody => Some ( StructRole :: LBody ) ,
1255- Self :: Table => Some ( StructRole :: Table ) ,
1256- Self :: TR => Some ( StructRole :: TR ) ,
1257- Self :: TH => Some ( StructRole :: TH ) ,
1258- Self :: TD => Some ( StructRole :: TD ) ,
1259- Self :: THead => Some ( StructRole :: THead ) ,
1260- Self :: TBody => Some ( StructRole :: TBody ) ,
1261- Self :: TFoot => Some ( StructRole :: TFoot ) ,
1262- Self :: Caption => Some ( StructRole :: Caption ) ,
1263- Self :: Figure => Some ( StructRole :: Figure ) ,
1264- Self :: Formula => Some ( StructRole :: Formula ) ,
1265- Self :: Artifact => None ,
1266- }
1267- }
1268-
1269- /// Return the closest equivalent role in the PDF 1.7 namespace.
1270- ///
1271- /// Returns `None` if the role exactly matches a PDF 1.7 role (see
1272- /// [`Self::into_pdf_1_7`]).
1273- ///
1274- /// There are three parameters governing the role mapping:
1216+ /// How the type should be represented in PDF 1.7.
12751217 ///
1276- /// - `map_hn_to_h6`: Are headings with levels higher than 6 are mapped to
1277- /// [`StructRole::H6`] (`true`) or [`StructRole::P`] (`false`)
1278- /// - `map_title_to_h1`: Is the `Title` role mapped to [`StructRole::H1`]
1279- /// (`true`) or to [`StructRole::P`] (`false`)
1280- /// - `map_sub_to_span`: Is the `Sub` role mapped to [`StructRole::Span`]
1281- /// (`true`) or to [`StructRole::Div`] (`false`)
1282- pub fn role_mapped_1_7 (
1283- self ,
1284- map_hn_to_h6 : bool ,
1285- map_title_to_h1 : bool ,
1286- map_sub_to_span : bool ,
1287- ) -> Option < StructRole > {
1218+ /// The `opts` parameter allows to control how certain roles are represented
1219+ /// in PDF 1.7. You can also use its default constructor.
1220+ pub fn compatibility_1_7 ( self , opts : RoleMapOpts ) -> StructRole2Compat {
12881221 match self {
1289- Self :: Document => None ,
1290- Self :: DocumentFragment => Some ( StructRole :: Div ) ,
1291- Self :: Part => None ,
1292- Self :: Sect => None ,
1293- Self :: Div => None ,
1294- Self :: Aside => Some ( StructRole :: Div ) ,
1295- Self :: NonStruct => None ,
1296- Self :: P => None ,
1297- Self :: Heading ( n) if ( 1u16 ..=6 ) . contains ( & n. get ( ) ) => None ,
1298- Self :: Heading ( _) => {
1299- Some ( if map_hn_to_h6 { StructRole :: H6 } else { StructRole :: P } )
1222+ Self :: Document => StructRole2Compat :: Compatible ( StructRole :: Document ) ,
1223+ Self :: DocumentFragment => StructRole2Compat :: RoleMapping ( StructRole :: Div ) ,
1224+ Self :: Part => StructRole2Compat :: Compatible ( StructRole :: Part ) ,
1225+ Self :: Sect => StructRole2Compat :: Compatible ( StructRole :: Sect ) ,
1226+ Self :: Div => StructRole2Compat :: Compatible ( StructRole :: Div ) ,
1227+ Self :: Aside => StructRole2Compat :: RoleMapping ( StructRole :: Div ) ,
1228+ Self :: NonStruct => StructRole2Compat :: Compatible ( StructRole :: NonStruct ) ,
1229+ Self :: P => StructRole2Compat :: Compatible ( StructRole :: P ) ,
1230+ Self :: Heading ( n) if n. get ( ) == 1 => {
1231+ StructRole2Compat :: Compatible ( StructRole :: H1 )
1232+ }
1233+ Self :: Heading ( n) if n. get ( ) == 2 => {
1234+ StructRole2Compat :: Compatible ( StructRole :: H2 )
13001235 }
1301- Self :: StructuredHeading => Some ( StructRole :: P ) ,
1302- Self :: Title => {
1303- Some ( if map_title_to_h1 { StructRole :: H1 } else { StructRole :: P } )
1236+ Self :: Heading ( n) if n. get ( ) == 3 => {
1237+ StructRole2Compat :: Compatible ( StructRole :: H3 )
13041238 }
1305- Self :: FENote => Some ( StructRole :: Note ) ,
1306- Self :: Sub => {
1307- Some ( if map_sub_to_span { StructRole :: Span } else { StructRole :: Div } )
1239+ Self :: Heading ( n) if n. get ( ) == 4 => {
1240+ StructRole2Compat :: Compatible ( StructRole :: H4 )
13081241 }
1309- Self :: Lbl => None ,
1310- Self :: Span => None ,
1311- Self :: Em => Some ( StructRole :: Span ) ,
1312- Self :: Strong => Some ( StructRole :: Span ) ,
1313- Self :: Link => None ,
1314- Self :: Annot => None ,
1315- Self :: Form => None ,
1316- Self :: Ruby => None ,
1317- Self :: RB => None ,
1318- Self :: RT => None ,
1319- Self :: Warichu => None ,
1320- Self :: WT => None ,
1321- Self :: WP => None ,
1322- Self :: L => None ,
1323- Self :: LI => None ,
1324- Self :: LBody => None ,
1325- Self :: Table => None ,
1326- Self :: TR => None ,
1327- Self :: TH => None ,
1328- Self :: TD => None ,
1329- Self :: THead => None ,
1330- Self :: TBody => None ,
1331- Self :: TFoot => None ,
1332- Self :: Caption => None ,
1333- Self :: Figure => None ,
1334- Self :: Formula => None ,
1335- Self :: Artifact => Some ( StructRole :: Private ) ,
1242+ Self :: Heading ( n) if n. get ( ) == 5 => {
1243+ StructRole2Compat :: Compatible ( StructRole :: H5 )
1244+ }
1245+ Self :: Heading ( n) if n. get ( ) == 6 => {
1246+ StructRole2Compat :: Compatible ( StructRole :: H6 )
1247+ }
1248+ Self :: Heading ( _) => StructRole2Compat :: RoleMapping (
1249+ if opts. contains ( RoleMapOpts :: map_hn_to_h6) {
1250+ StructRole :: H6
1251+ } else {
1252+ StructRole :: P
1253+ } ,
1254+ ) ,
1255+ Self :: StructuredHeading => StructRole2Compat :: RoleMapping ( StructRole :: P ) ,
1256+ Self :: Title => StructRole2Compat :: RoleMapping (
1257+ if opts. contains ( RoleMapOpts :: map_title_to_h1) {
1258+ StructRole :: H1
1259+ } else {
1260+ StructRole :: P
1261+ } ,
1262+ ) ,
1263+ Self :: FENote => StructRole2Compat :: RoleMapping ( StructRole :: Note ) ,
1264+ Self :: Sub => StructRole2Compat :: RoleMapping (
1265+ if opts. contains ( RoleMapOpts :: map_sub_to_span) {
1266+ StructRole :: Span
1267+ } else {
1268+ StructRole :: Div
1269+ } ,
1270+ ) ,
1271+ Self :: Lbl => StructRole2Compat :: Compatible ( StructRole :: Lbl ) ,
1272+ Self :: Span => StructRole2Compat :: Compatible ( StructRole :: Span ) ,
1273+ Self :: Em => StructRole2Compat :: RoleMapping ( StructRole :: Span ) ,
1274+ Self :: Strong => StructRole2Compat :: RoleMapping ( StructRole :: Span ) ,
1275+ Self :: Link => StructRole2Compat :: Compatible ( StructRole :: Link ) ,
1276+ Self :: Annot => StructRole2Compat :: Compatible ( StructRole :: Annot ) ,
1277+ Self :: Form => StructRole2Compat :: Compatible ( StructRole :: Form ) ,
1278+ Self :: Ruby => StructRole2Compat :: Compatible ( StructRole :: Ruby ) ,
1279+ Self :: RB => StructRole2Compat :: Compatible ( StructRole :: RB ) ,
1280+ Self :: RT => StructRole2Compat :: Compatible ( StructRole :: RT ) ,
1281+ Self :: Warichu => StructRole2Compat :: Compatible ( StructRole :: Warichu ) ,
1282+ Self :: WT => StructRole2Compat :: Compatible ( StructRole :: WT ) ,
1283+ Self :: WP => StructRole2Compat :: Compatible ( StructRole :: WP ) ,
1284+ Self :: L => StructRole2Compat :: Compatible ( StructRole :: L ) ,
1285+ Self :: LI => StructRole2Compat :: Compatible ( StructRole :: LI ) ,
1286+ Self :: LBody => StructRole2Compat :: Compatible ( StructRole :: LBody ) ,
1287+ Self :: Table => StructRole2Compat :: Compatible ( StructRole :: Table ) ,
1288+ Self :: TR => StructRole2Compat :: Compatible ( StructRole :: TR ) ,
1289+ Self :: TH => StructRole2Compat :: Compatible ( StructRole :: TH ) ,
1290+ Self :: TD => StructRole2Compat :: Compatible ( StructRole :: TD ) ,
1291+ Self :: THead => StructRole2Compat :: Compatible ( StructRole :: THead ) ,
1292+ Self :: TBody => StructRole2Compat :: Compatible ( StructRole :: TBody ) ,
1293+ Self :: TFoot => StructRole2Compat :: Compatible ( StructRole :: TFoot ) ,
1294+ Self :: Caption => StructRole2Compat :: Compatible ( StructRole :: Caption ) ,
1295+ Self :: Figure => StructRole2Compat :: Compatible ( StructRole :: Figure ) ,
1296+ Self :: Formula => StructRole2Compat :: Compatible ( StructRole :: Formula ) ,
1297+ Self :: Artifact => StructRole2Compat :: RoleMapping ( StructRole :: Private ) ,
13361298 }
13371299 }
13381300
@@ -1377,11 +1339,75 @@ impl StructRole2 {
13771339 }
13781340}
13791341
1342+ bitflags:: bitflags! {
1343+ /// Options for mapping PDF 2.0 [`StructRole2`] to PDF 1.7 [`StructRole`].
1344+ pub struct RoleMapOpts : u8 {
1345+ /// Whether to map headings with levels higher than 6 to [`StructRole::H6`]
1346+ /// (`true`) or [`StructRole::P`] (`false`).
1347+ const map_hn_to_h6 = 1 << 0 ;
1348+ /// Whether to map the `Title` role to [`StructRole::H1`] (`true`) or
1349+ /// [`StructRole::P`] (`false`).
1350+ const map_title_to_h1 = 1 << 1 ;
1351+ /// Whether to map the `Sub` role to [`StructRole::Span`] (`true`) or
1352+ /// [`StructRole::Div`] (`false`).
1353+ const map_sub_to_span = 1 << 2 ;
1354+ }
1355+ }
1356+
1357+ impl Default for RoleMapOpts {
1358+ fn default ( ) -> Self {
1359+ Self :: empty ( )
1360+ }
1361+ }
1362+
1363+ /// How a particular PDF 2.0 [`StructRole2`] can be represented in PDF 1.7.
1364+ #[ derive( Debug , Copy , Clone , Eq , PartialEq , Hash ) ]
1365+ pub enum StructRole2Compat {
1366+ /// The role is a direct match with this PDF 1.7 role.
1367+ Compatible ( StructRole ) ,
1368+ /// The has no direct match with a PDF 1.7 role, but can be mapped to
1369+ /// a PDF 1.7 role with a similar meaning.
1370+ RoleMapping ( StructRole ) ,
1371+ }
1372+
1373+ impl StructRole2Compat {
1374+ /// Return the corresponding PDF 1.7 [`StructRole`] for this role or `None`
1375+ /// if there is no exact match.
1376+ pub fn into_pdf_1_7 ( self ) -> Option < StructRole > {
1377+ match self {
1378+ Self :: Compatible ( role) => Some ( role) ,
1379+ Self :: RoleMapping ( _) => None ,
1380+ }
1381+ }
1382+
1383+ /// Return the closest equivalent role in the PDF 1.7 namespace.
1384+ ///
1385+ /// Returns `None` if the role exactly matches a PDF 1.7 role (see
1386+ /// [`Self::into_pdf_1_7`]).
1387+ pub fn role_mapped_1_7 ( self ) -> Option < StructRole > {
1388+ match self {
1389+ Self :: Compatible ( _) => None ,
1390+ Self :: RoleMapping ( role) => Some ( role) ,
1391+ }
1392+ }
1393+
1394+ /// Return the inner role.
1395+ pub fn role ( self ) -> StructRole {
1396+ match self {
1397+ Self :: Compatible ( role) => role,
1398+ Self :: RoleMapping ( role) => role,
1399+ }
1400+ }
1401+ }
1402+
13801403impl TryFrom < StructRole2 > for StructRole {
13811404 type Error = ( ) ;
13821405
13831406 fn try_from ( value : StructRole2 ) -> Result < Self , Self :: Error > {
1384- value. into_pdf_1_7 ( ) . ok_or ( ( ) )
1407+ value
1408+ . compatibility_1_7 ( RoleMapOpts :: default ( ) )
1409+ . into_pdf_1_7 ( )
1410+ . ok_or ( ( ) )
13851411 }
13861412}
13871413
0 commit comments