| Server IP : 37.9.174.138 / Your IP : 216.73.216.117 Web Server : Apache System : Linux vps6.backend.sk 6.12.100+deb13-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.12.100-1 (2026-07-30) x86_64 User : ftpuser ( 1001) PHP Version : 8.4.24 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /lib/python3/dist-packages/psutils/ |
Upload File : |
"""
PSUtils document reader classes.
Copyright (c) Reuben Thomas 2023.
Released under the GPL version 3, or (at your option) any later version.
"""
from pathlib import Path
import re
from typing import List, Tuple, Union, Type, IO
from pypdf import PdfReader as PdfReaderBase
from pypdf._utils import StrByteType
from .types import Rectangle
from .warnings import die
class PdfReader(PdfReaderBase):
def __init__(
self,
stream: Union[StrByteType, Path],
strict: bool = False,
password: Union[str, bytes, None] = None,
) -> None:
super().__init__(stream, strict, password)
assert len(self.pages) > 0
mediabox = self.pages[0].mediabox
self.size = Rectangle(mediabox.width, mediabox.height)
self.size_guessed = False
size_keywords = (
b"DocumentMedia",
b"PageBoundingBox",
b"HiResBoundingBox",
b"BoundingBox",
)
# FIXME: Store lists of lines, not file offsets.
class PsReader: # pylint: disable=too-many-instance-attributes,too-few-public-methods
def __init__(self, infile: IO[bytes]) -> None:
self.infile = infile
self.headerpos: int = 0
self.pagescmt: int = 0
self.endsetup: int = 0
self.procset_pos: range = range(0, 0) # pstops procset location
self.num_pages: int = 0
self.sizeheaders: List[int] = []
self.pageptr: List[int] = []
self.size = None
self.size_guessed = False
nesting = 0
self.infile.seek(0)
record, next_record, buffer = 0, 0, None
file_sizes = {}
for buffer in self.infile:
next_record += len(buffer)
if buffer.startswith(b"%%"):
keyword, value = self.comment(buffer)
if keyword is not None:
# If input paper size is not set, try to read it
if (
self.headerpos == 0
and self.size is None
and keyword in size_keywords
):
assert value is not None
words = value.split(b" ")
if keyword == b"DocumentMedia" and len(words) > 2:
w = words[1].decode("utf-8", "ignore")
h = words[2].decode("utf-8", "ignore")
try:
file_sizes[keyword] = Rectangle(float(w), float(h))
except ValueError:
pass
elif len(words) == 4:
llx = words[0].decode("utf-8", "ignore")
lly = words[1].decode("utf-8", "ignore")
urx = words[2].decode("utf-8", "ignore")
ury = words[3].decode("utf-8", "ignore")
try:
file_sizes[keyword] = Rectangle(
float(urx) - float(llx), float(ury) - float(lly)
)
except ValueError:
pass
if nesting == 0 and keyword == b"Page":
self.pageptr.append(record)
elif self.headerpos == 0 and (
keyword in size_keywords or keyword == b"DocumentPaperSizes"
):
self.sizeheaders.append(record)
elif self.headerpos == 0 and keyword == b"Pages":
self.pagescmt = record
elif self.headerpos == 0 and keyword == b"EndComments":
self.headerpos = next_record
elif keyword in [
b"BeginDocument",
b"BeginBinary",
b"Begself.infile",
]:
nesting += 1
elif keyword in [b"EndDocument", b"EndBinary", b"EndFile"]:
nesting -= 1
elif nesting == 0 and keyword == b"EndSetup":
self.endsetup = record
elif nesting == 0 and keyword == b"BeginProlog":
self.headerpos = next_record
elif nesting == 0 and buffer == b"%%BeginProcSet: PStoPS":
self.procset_pos = range(record, 0)
elif (
self.procset_pos.start > 0
and self.procset_pos.stop == 0
and keyword == b"EndProcSet"
):
self.procset_pos = range(self.procset_pos.start, next_record)
elif nesting == 0 and keyword in [b"Trailer", b"EOF"]:
break
elif self.headerpos == 0:
self.headerpos = record
record = next_record
# If paper size was not already set, and we found a possible size in
# the file, use it.
if self.size is None and len(file_sizes) > 0:
for keyword in size_keywords:
file_size = file_sizes.get(keyword)
if (
file_size is not None
and file_size.width != 0
and file_size.height != 0
):
self.size = file_size
if keyword in (b"BoundingBox", b"HiResBoundingBox"):
self.size_guessed = True
break
self.num_pages = len(self.pageptr)
self.pageptr.append(record)
if self.endsetup == 0 or self.endsetup > self.pageptr[0]:
self.endsetup = self.pageptr[0]
# Return comment keyword and value if `line' is a DSC comment
def comment(self, line: bytes) -> Union[Tuple[bytes, bytes], Tuple[None, None]]:
m = re.match(b"%%([^:]+):?\\s+?(.*\\S?)\\s*$", line)
return (m[1], m[2]) if m else (None, None)
def document_reader(file: IO[bytes], file_type: str) -> Union[PdfReader, PsReader]:
constructor: Union[Type[PdfReader], Type[PsReader]]
if file_type in (".ps", ".eps"):
constructor = PsReader
elif file_type == ".pdf":
constructor = PdfReader
else:
die(f"incompatible file type `{file_type}'")
return constructor(file)