Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/pypdf/generic/_viewerpref.py: 24%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

79 statements  

1# Copyright (c) 2023, Pubpub-ZZ 

2# 

3# All rights reserved. 

4# 

5# Redistribution and use in source and binary forms, with or without 

6# modification, are permitted provided that the following conditions are 

7# met: 

8# 

9# * Redistributions of source code must retain the above copyright notice, 

10# this list of conditions and the following disclaimer. 

11# * Redistributions in binary form must reproduce the above copyright notice, 

12# this list of conditions and the following disclaimer in the documentation 

13# and/or other materials provided with the distribution. 

14# * The name of the author may not be used to endorse or promote products 

15# derived from this software without specific prior written permission. 

16# 

17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 

18# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 

19# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 

20# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 

21# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 

22# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 

23# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 

24# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 

25# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 

26# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 

27# POSSIBILITY OF SUCH DAMAGE. 

28 

29from typing import ( 

30 Any, 

31 Optional, 

32 cast, 

33) 

34 

35from ..constants import PageAttributes 

36from ._base import BooleanObject, NameObject, NumberObject, is_null_or_none 

37from ._data_structures import ArrayObject, DictionaryObject 

38 

39f_obj = BooleanObject(False) 

40 

41#: The page boundaries a viewer preference may name, per Table 147 in the 2.0 

42#: reference. 

43BOX_NAMES = [ 

44 PageAttributes.MEDIABOX, 

45 PageAttributes.CROPBOX, 

46 PageAttributes.BLEEDBOX, 

47 PageAttributes.TRIMBOX, 

48 PageAttributes.ARTBOX, 

49] 

50 

51 

52class ViewerPreferences(DictionaryObject): 

53 def __init__(self, obj: Optional[DictionaryObject] = None) -> None: 

54 super().__init__(self) 

55 if not is_null_or_none(obj): 

56 self.update(obj.items()) # type: ignore[union-attr] 

57 try: 

58 self.indirect_reference = obj.indirect_reference # type: ignore[union-attr] 

59 except AttributeError: 

60 pass 

61 

62 def _get_bool(self, key: str, default: Optional[BooleanObject]) -> Optional[BooleanObject]: 

63 return self.get(key, default) 

64 

65 def _set_bool(self, key: str, v: bool) -> None: 

66 self[NameObject(key)] = BooleanObject(v is True) 

67 

68 def _get_name(self, key: str, default: Optional[NameObject]) -> Optional[NameObject]: 

69 return self.get(key, default) 

70 

71 def _set_name(self, key: str, lst: list[str], v: NameObject) -> None: 

72 if v[0] != "/": 

73 raise ValueError(f"{v} does not start with '/'") 

74 if lst != [] and v not in lst: 

75 raise ValueError(f"{v} is an unacceptable value") 

76 self[NameObject(key)] = NameObject(v) 

77 

78 def _get_arr(self, key: str, default: Optional[list[Any]]) -> Optional[ArrayObject]: 

79 return self.get(key, None if default is None else ArrayObject(default)) 

80 

81 def _set_arr(self, key: str, v: Optional[ArrayObject]) -> None: 

82 if v is None: 

83 try: 

84 del self[NameObject(key)] 

85 except KeyError: 

86 pass 

87 return 

88 if not isinstance(v, ArrayObject): 

89 raise ValueError("ArrayObject is expected") 

90 if key == "/PrintPageRange" and len(v) % 2: 

91 # The array holds first/last page pairs, so an odd length leaves a 

92 # range without its end. 

93 raise ValueError( 

94 f"/PrintPageRange holds page pairs, got {len(v)} entries: {v}" 

95 ) 

96 self[NameObject(key)] = v 

97 

98 def _get_int(self, key: str, default: Optional[NumberObject]) -> Optional[NumberObject]: 

99 return self.get(key, default) 

100 

101 def _set_int(self, key: str, v: int) -> None: 

102 if v < 0: 

103 raise ValueError(f"{v} is an unacceptable value for {key}") 

104 self[NameObject(key)] = NumberObject(v) 

105 

106 @property 

107 def PRINT_SCALING(self) -> NameObject: 

108 return NameObject("/PrintScaling") 

109 

110 def __new__(cls: Any, value: Any = None) -> "ViewerPreferences": # noqa: PYI034 

111 def _add_prop_bool(key: str, default: Optional[BooleanObject]) -> property: 

112 return property( 

113 lambda self: self._get_bool(key, default), 

114 lambda self, v: self._set_bool(key, v), 

115 None, 

116 f""" 

117 Returns/Modify the status of {key}, Returns {default} if not defined 

118 """, 

119 ) 

120 

121 def _add_prop_name( 

122 key: str, lst: list[str], default: Optional[NameObject] 

123 ) -> property: 

124 return property( 

125 lambda self: self._get_name(key, default), 

126 lambda self, v: self._set_name(key, lst, v), 

127 None, 

128 f""" 

129 Returns/Modify the status of {key}, Returns {default} if not defined. 

130 Acceptable values: {lst} 

131 """, 

132 ) 

133 

134 def _add_prop_arr(key: str, default: Optional[ArrayObject]) -> property: 

135 return property( 

136 lambda self: self._get_arr(key, default), 

137 lambda self, v: self._set_arr(key, v), 

138 None, 

139 f""" 

140 Returns/Modify the status of {key}, Returns {default} if not defined 

141 """, 

142 ) 

143 

144 def _add_prop_int(key: str, default: Optional[int]) -> property: 

145 return property( 

146 lambda self: self._get_int(key, default), 

147 lambda self, v: self._set_int(key, v), 

148 None, 

149 f""" 

150 Returns/Modify the status of {key}, Returns {default} if not defined 

151 """, 

152 ) 

153 

154 cls.hide_toolbar = _add_prop_bool("/HideToolbar", f_obj) 

155 cls.hide_menubar = _add_prop_bool("/HideMenubar", f_obj) 

156 cls.hide_windowui = _add_prop_bool("/HideWindowUI", f_obj) 

157 cls.fit_window = _add_prop_bool("/FitWindow", f_obj) 

158 cls.center_window = _add_prop_bool("/CenterWindow", f_obj) 

159 cls.display_doctitle = _add_prop_bool("/DisplayDocTitle", f_obj) 

160 

161 cls.non_fullscreen_pagemode = _add_prop_name( 

162 "/NonFullScreenPageMode", 

163 ["/UseNone", "/UseOutlines", "/UseThumbs", "/UseOC"], 

164 NameObject("/UseNone"), 

165 ) 

166 cls.direction = _add_prop_name( 

167 "/Direction", ["/L2R", "/R2L"], NameObject("/L2R") 

168 ) 

169 cls.view_area = _add_prop_name("/ViewArea", BOX_NAMES, None) 

170 cls.view_clip = _add_prop_name("/ViewClip", BOX_NAMES, None) 

171 cls.print_area = _add_prop_name("/PrintArea", BOX_NAMES, None) 

172 cls.print_clip = _add_prop_name("/PrintClip", BOX_NAMES, None) 

173 cls.print_scaling = _add_prop_name( 

174 "/PrintScaling", ["/None", "/AppDefault"], None 

175 ) 

176 cls.duplex = _add_prop_name( 

177 "/Duplex", ["/Simplex", "/DuplexFlipShortEdge", "/DuplexFlipLongEdge"], None 

178 ) 

179 cls.pick_tray_by_pdfsize = _add_prop_bool("/PickTrayByPDFSize", None) 

180 cls.print_pagerange = _add_prop_arr("/PrintPageRange", None) 

181 cls.num_copies = _add_prop_int("/NumCopies", None) 

182 

183 cls.enforce = _add_prop_arr("/Enforce", ArrayObject()) 

184 

185 return cast("ViewerPreferences", DictionaryObject.__new__(cls))