Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions changes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@ Change Log
==========


**Changes in version **

* Fixed issues:

* Other:

* Fixed incorrect generation of `lineJoin j` in PDF content, introduced in 1.27.2.2.


**Changes in version 1.27.2.2** (2026-03-20)

* Fixed issues:
Expand Down
78 changes: 39 additions & 39 deletions src/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1223,9 +1223,9 @@ def popup_rect(self):
obj = mupdf.pdf_dict_get( annot_obj, PDF_NAME('Popup'))
if obj.m_internal:
rect = mupdf.pdf_dict_get_rect(obj, PDF_NAME('Rect'))
#log( '{rect=}')
#log(f'{rect=}')
val = JM_py_from_rect(rect)
#log( '{val=}')
#log(f'{val=}')

val = Rect(val) * self.get_parent().transformation_matrix
val *= self.get_parent().derotation_matrix
Expand Down Expand Up @@ -3234,10 +3234,10 @@ def cre_annot(lnk, xref_dst, pno_src, ctm):
for i in range(len(xref_src)):
page_src = doc2[pno_src[i]] # load source page
links = page_src.get_links() # get all its links
#log( '{pno_src=}')
#log( '{type(page_src)=}')
#log( '{page_src=}')
#log( '{=i len(links)}')
#log(f'{pno_src=}')
#log(f'{type(page_src)=}')
#log(f'{page_src=}')
#log(f'{=i len(links)}')
if len(links) == 0: # no links there
page_src = None
continue
Expand Down Expand Up @@ -4555,7 +4555,7 @@ def extract_font(self, xref=0, info_only=0, named=None):
'''
Get a font by xref. Returns a tuple or dictionary.
'''
#log( '{=xref info_only}')
#log(f'{=xref info_only}')
pdf = _as_pdf_document(self)
obj = mupdf.pdf_load_object(pdf, xref)
type_ = mupdf.pdf_dict_get(obj, PDF_NAME('Type'))
Expand Down Expand Up @@ -8278,7 +8278,7 @@ def flags(self):
if not f:
return
assert isinstance( f, mupdf.fz_font_flags_t)
#log( '{=f}')
#log(f'{f=}')
if mupdf_cppyy:
# cppyy includes remaining higher bits.
v = [f.is_mono]
Expand Down Expand Up @@ -8396,7 +8396,7 @@ def is_writable(self):
@property
def name(self):
ret = mupdf.fz_font_name(self.this)
#log( '{ret=}')
#log(f'{ret=}')
return ret

def text_length(self, text, fontsize=11, language=None, script=0, wmode=0, small_caps=0):
Expand Down Expand Up @@ -9952,7 +9952,7 @@ def _get_optional_content(self, oc: OptInt) -> OptStr:
i += 1
mc = f"MC{i:d}"
self._set_resource_property(mc, oc)
#log( 'returning {mc=}')
#log(f'returning {mc=}')
return mc

def _get_resource_properties(self):
Expand Down Expand Up @@ -12773,7 +12773,7 @@ def load_widget( self, xref):

page = _as_pdf_page(self.this)
annot = JM_get_widget_by_xref( page, xref)
#log( '{=type(annot)}')
#log(f'{type(annot)=}')
val = annot
if not val:
return val
Expand Down Expand Up @@ -13159,7 +13159,7 @@ def widgets(self, types=None):
will only yield text fields.
"""
#for a in self.annot_xrefs():
# log( '{a=}')
# log(f'{a=}')
widget_xrefs = [a[0] for a in self.annot_xrefs() if a[1] == mupdf.PDF_ANNOT_WIDGET]
#log(f'widgets(): {widget_xrefs=}')
for xref in widget_xrefs:
Expand Down Expand Up @@ -13401,7 +13401,7 @@ def __init__(self, *args):
pm_alpha = pm.alpha()
src_stride = src_pix.stride()
src_n = src_pix.n()
#log( '{=pm_stride pm_n src_stride src_n}')
#log(f'{pm_stride pm_n src_stride src_n=}')
for y in range( h):
for x in range( w):
pm_i = pm_stride * y + pm_n * x
Expand Down Expand Up @@ -15761,7 +15761,7 @@ def finish(
if lineCap != 0:
self.draw_cont = f"{lineCap} J\n" + self.draw_cont
if lineJoin != 0:
self.draw_cont = "{lineJoin} j\n" + self.draw_cont
self.draw_cont = f"{lineJoin} j\n" + self.draw_cont

if dashes not in (None, "", "[] 0"):
self.draw_cont = f"{dashes} d\n" + self.draw_cont
Expand Down Expand Up @@ -16755,20 +16755,20 @@ def _bbox(self):
def append(self, pos, text, font=None, fontsize=11, language=None, right_to_left=0, small_caps=0):
"""Store 'text' at point 'pos' using 'font' and 'fontsize'."""
pos = Point(pos) * self.ictm
#log( '{font=}')
#log(f'{font=}')
if font is None:
font = Font("helv")
if not font.is_writable:
if 0:
log( '{font.this.m_internal.name=}')
log( '{font.this.m_internal.t3matrix=}')
log( '{font.this.m_internal.bbox=}')
log( '{font.this.m_internal.glyph_count=}')
log( '{font.this.m_internal.use_glyph_bbox=}')
log( '{font.this.m_internal.width_count=}')
log( '{font.this.m_internal.width_default=}')
log( '{font.this.m_internal.has_digest=}')
log( 'Unsupported font {font.name=}')
log(f'{font.this.m_internal.name=}')
log(f'{font.this.m_internal.t3matrix=}')
log(f'{font.this.m_internal.bbox=}')
log(f'{font.this.m_internal.glyph_count=}')
log(f'{font.this.m_internal.use_glyph_bbox=}')
log(f'{font.this.m_internal.width_count=}')
log(f'{font.this.m_internal.width_default=}')
log(f'{font.this.m_internal.has_digest=}')
log(f'Unsupported font {font.name=}')
if mupdf_cppyy:
import cppyy
log( f'Unsupported font {cppyy.gbl.mupdf_font_name(font.this.m_internal)=}')
Expand Down Expand Up @@ -17123,7 +17123,7 @@ def write_text(self, page, color=None, opacity=-1, overlay=1, morph=None, matrix
resources = mupdf.pdf_new_dict(pdfpage.doc(), 5)
contents = mupdf.fz_new_buffer(1024)
dev = mupdf.pdf_new_pdf_device( pdfpage.doc(), mupdf.FzMatrix(), resources, contents)
#log( '=== {dev_color!r=}')
#log(f'=== {dev_color!r=}')
mupdf.fz_fill_text(
dev,
self.this,
Expand Down Expand Up @@ -19051,7 +19051,7 @@ def JM_compress_buffer(inbuffer):
inbuffer,
mupdf.FZ_DEFLATE_BEST,
)
#log( '{=data compressed_length}')
#log(f'{data compressed_length=}')
if not data or compressed_length == 0:
return None
buf = mupdf.FzBuffer(mupdf.fz_new_buffer_from_data(data, compressed_length))
Expand Down Expand Up @@ -19816,7 +19816,7 @@ def JM_get_fontbuffer(doc, xref):
elif mupdf.pdf_name_eq(obj, PDF_NAME('OpenType')):
pass # Prev code did: ext = "otf", but this has no effect. */
else:
message('warning: unhandled font type {pdf_to_name(ctx, obj)!r}')
message(f'warning: unhandled font type {mupdf.pdf_to_name(obj)!r}')

if not stream:
message('warning: unhandled font type')
Expand Down Expand Up @@ -19869,7 +19869,7 @@ def JM_get_widget_properties(annot, Widget):
Populate a Python Widget object with the values from a PDF form field.
Called by "Page.first_widget" and "Widget.next".
'''
#log( '{type(annot)=}')
#log(f'{type(annot)=}')
annot_obj = mupdf.pdf_annot_obj(annot.this)
#log( 'Have called mupdf.pdf_annot_obj()')
page = _pdf_annot_page(annot.this)
Expand Down Expand Up @@ -20219,7 +20219,7 @@ def JM_image_profile( imagedata, keep_image):
message( "bad image data")
return None
c = imagedata
#log( 'calling mfz_recognize_image_format with {c!r=}')
#log(f'calling mfz_recognize_image_format with {c!r=}')
type_ = mupdf.fz_recognize_image_format( c)
if type_ == mupdf.FZ_IMAGE_UNKNOWN:
return None
Expand Down Expand Up @@ -20738,7 +20738,7 @@ def JM_make_textpage_dict(tp, page_dict, raw):
block_list = []
tp_rect = mupdf.FzRect(tp.m_internal.mediabox)
block_n = -1
#log( 'JM_make_textpage_dict {=tp}')
#log(f'JM_make_textpage_dict {=tp}')
for block in tp:
block_n += 1
if (not mupdf.fz_contains_rect(tp_rect, mupdf.FzRect(block.m_internal.bbox))
Expand Down Expand Up @@ -21173,7 +21173,7 @@ def JM_print_stext_page_as_text(res, page):
):
#raw += chr(ch.m_internal.c)
last_char = ch.m_internal.c
#log( '{=last_char!r utf!r}')
#log(f'{=last_char!r utf!r}')
JM_append_rune(res, last_char)
if last_char != 10 and last_char > 0:
mupdf.fz_append_string(res, "\n")
Expand Down Expand Up @@ -21365,20 +21365,20 @@ def JM_rotate_page_matrix(page):
if not page.m_internal:
return mupdf.FzMatrix() # no valid pdf page given
rotation = JM_page_rotation(page)
#log( '{rotation=}')
#log(f'{rotation=}')
if rotation == 0:
return mupdf.FzMatrix() # no rotation
cb_size = JM_cropbox_size(page.obj())
w = cb_size.x
h = cb_size.y
#log( '{=h w}')
#log(f'{=h w}')
if rotation == 90:
m = mupdf.fz_make_matrix(0, 1, -1, 0, h, 0)
elif rotation == 180:
m = mupdf.fz_make_matrix(-1, 0, 0, -1, w, h)
else:
m = mupdf.fz_make_matrix(0, -1, 1, 0, 0, w)
#log( 'returning {m=}')
#log(f'returning {m=}')
return m


Expand Down Expand Up @@ -22401,7 +22401,7 @@ def get_tessdata(tessdata=None):
if os.path.exists(tessdata): # all ok?
return tessdata
else: # should not happen!
raise RuntimeError("No tessdata specified and Tesseract installation has no {tessdata} folder")
raise RuntimeError(f"No tessdata specified and Tesseract installation has no {tessdata} folder")

# Unix-like systems:
attempts = list()
Expand Down Expand Up @@ -22593,7 +22593,7 @@ def append():
dev.pathdict.clear()
assert isinstance(dev.out, list)
len_ = len(dev.out) # len of output list so far
#log('{len_=}')
#log(f'{len_=}')
if len_ == 0: # always append first path
return append()
#log(f'{getattr(dev, "pathdict", None)=}')
Expand Down Expand Up @@ -23129,12 +23129,12 @@ def moveto(self, ctx, x, y): # trace_moveto().
if 0 and isinstance(self.dev.pathdict, dict):
log(f'self.dev.pathdict:')
for n, v in self.dev.pathdict.items():
log( ' {type(n)=} {len(n)=} {n!r} {n}: {v!r}: {v}')
log(f' {type(n)=} {len(n)=} {n!r} {n}: {v!r}: {v}')

#log(f'Walker(): {type(self.dev.pathdict)=} {self.dev.pathdict=}')

try:
#log( '{=dev.ctm type(dev.ctm)}')
#log(f'{dev.ctm type(dev.ctm)=}')
self.dev.lastpoint = mupdf.fz_transform_point(
mupdf.fz_make_point(x, y),
self.dev.ctm,
Expand Down Expand Up @@ -24314,7 +24314,7 @@ def page_merge(doc_des, doc_src, page_from, page_to, rotate, links, copy_annots,
for i in range( len(known_page_objs)):
obj = mupdf.pdf_dict_get_inheritable( page_ref, known_page_objs[i])
if obj.m_internal:
#log( '{=type(graft_map) type(graft_map.this)}')
#log(f'{type(graft_map) type(graft_map.this)=}')
mupdf.pdf_dict_put( page_dict, known_page_objs[i], mupdf.pdf_graft_mapped_object(graft_map.this, obj))

# Copy annotations, but skip Link, Popup, IRT, Widget types
Expand Down
Loading