diff --git a/src/__init__.py b/src/__init__.py index 910862111..7db1d1c47 100644 --- a/src/__init__.py +++ b/src/__init__.py @@ -5767,6 +5767,23 @@ def layout(self, rect=None, width=0, height=0, fontsize=11): self._reset_page_refs() self.init_doc() + def apply_css(self, css: str, append: bool = True): + """Apply CSS to a reflowable document. + + If 'append' evaluates to True, the CSS will be appended to + the default CSS of this document type. + Otherwise the default CSS will be ignored. + """ + if self.is_closed or self.is_encrypted: + raise ValueError("document closed or encrypted") + doc = self.this + if not mupdf.fz_is_document_reflowable(doc): + return + if not isinstance(css, str) or not css: + return + append = int(bool(append)) # ensure integer + mupdf.fz_style_document(doc, append, css) + def load_page(self, page_id): """Load a page. @@ -19107,6 +19124,12 @@ def JM_convert_to_pdf(doc, fp, tp, rotate) -> bytes: Convert any MuPDF document to a PDF Returns bytes object containing the PDF, created via 'write' function. ''' + + def loc_to_pno(doc, loc): + """Convert location to page number.""" + pno = sum(mupdf.fz_count_chapter_pages(doc, i) for i in range(loc.chapter)) + return pno + loc.page + pdfout = mupdf.PdfDocument() incr = 1 s = fp @@ -19117,6 +19140,7 @@ def JM_convert_to_pdf(doc, fp, tp, rotate) -> bytes: e = fp # ... range rot = JM_norm_rotation(rotate) i = fp + pno = -1 # init current PDF page number internal_links = [] # collect PDF-wide internal links here while 1: # interpret & write document pages as PDF pages if not _INRANGE(i, s, e): @@ -19129,10 +19153,11 @@ def JM_convert_to_pdf(doc, fp, tp, rotate) -> bytes: dev = None page_obj = mupdf.pdf_add_page(pdfout, mediabox, rot, resources, contents) mupdf.pdf_insert_page(pdfout, -1, page_obj) + pno += 1 # also copy links to the output PDF page # get the PDF page we've just created - pdf_page = mupdf.pdf_load_page(pdfout, i) + pdf_page = mupdf.pdf_load_page(pdfout, pno) # loop through source page links link = mupdf.fz_load_links(page) # load first link @@ -19146,29 +19171,42 @@ def JM_convert_to_pdf(doc, fp, tp, rotate) -> bytes: else: # internal links done when PDF is complete # find target of internal link ret, xp, yp = mupdf.fz_resolve_link(doc, uri) - ilink={"page": i, "ret": ret, "from": rect, "h": rect.y1-rect.y0, "w": rect.x1-rect.x0, "xp": xp, "yp": yp} - internal_links.append(ilink) + if ret.chapter > -1 and ret.page > -1: + ilink = {"page": pno, + "ret": ret, + "from": rect, + "h": rect.y1 - rect.y0, + "w": rect.x1 - rect.x0, + "xp": xp, + "yp": yp, + } + internal_links.append(ilink) link = link.next() - + i += incr - # PDF created - now write it to Python bytearray # insert any internal links collected before: + pno = None # init PDF page number for ilink in internal_links: - pdf_page = mupdf.pdf_load_page(pdfout, ilink["page"]) + this_pno = ilink["page"] + if pno != this_pno: + pdf_page = mupdf.pdf_load_page(pdfout, this_pno) + pno = this_pno ret = ilink["ret"] dest = mupdf.fz_link_dest() - dest.type = 7 # XYZ destination format - dest.loc.chapter = ret.chapter - dest.loc.page = ret.page + dest.type = mupdf.FZ_LINK_DEST_XYZ + dest.loc.chapter = 0 # PDFs have 1 chapter + dest.loc.page = loc_to_pno(doc, ret) dest.h = ilink["h"] dest.w = ilink["w"] dest.x = ilink["xp"] dest.y = ilink["yp"] dest.zoom = 0 - rect=ilink["from"] + rect = ilink["from"] uri = mupdf.pdf_new_uri_from_explicit_dest(mupdf.FzLinkDest(dest)) mupdf.pdf_create_link(pdf_page, rect, uri) + + # PDF created - now write it out # prepare write options structure opts = mupdf.PdfWriteOptions() opts.do_garbage = 3