Skip to content
Open
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
14 changes: 9 additions & 5 deletions src/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21544,13 +21544,18 @@ def JM_new_buffer_from_stext_page(page):
for block in page:
if block.m_internal.type == mupdf.FZ_STEXT_BLOCK_TEXT:
for line in block:
break_line = True
for ch in line:
if (not JM_rects_overlap(rect, JM_char_bbox(line, ch))
and not mupdf.fz_is_infinite_rect(rect)
):
continue
mupdf.fz_append_rune(buf, ch.m_internal.c)
mupdf.fz_append_byte(buf, ord('\n'))
if not ch.m_internal.next and (line.m_internal.flags & mupdf.FZ_STEXT_LINE_FLAGS_JOINED):
break_line = 0
else:
mupdf.fz_append_rune(buf, ch.m_internal.c)
if break_line:
mupdf.fz_append_byte(buf, ord('\n'))
mupdf.fz_append_byte(buf, ord('\n'))
return buf

Expand Down Expand Up @@ -22031,9 +22036,8 @@ def __str__(self):
break
haystack += 1
#next_char:;
assert haystack_string[haystack] == '\n', \
f'{haystack=} {haystack_string[haystack]=}'
haystack += 1
if haystack_string[haystack] == '\n':
haystack += 1
assert haystack_string[haystack] == '\n', \
f'{haystack=} {haystack_string[haystack]=}'
haystack += 1
Expand Down
43 changes: 33 additions & 10 deletions src/extra.i
Original file line number Diff line number Diff line change
Expand Up @@ -788,6 +788,10 @@ static void JM_set_annot_callout_line(mupdf::PdfAnnot& annot, PyObject *callout,
{
fz_point points[3];
mupdf::FzPoint p;
if (count > sizeof(points)/sizeof(points[0]))
{
throw std::runtime_error(MSG_BAD_ARG_POINTS);
}
for (int i = 0; i < count; i++)
{
p = JM_point_from_py(PyTuple_GetItem(callout, (Py_ssize_t) i));
Expand Down Expand Up @@ -2301,16 +2305,23 @@ void _as_text(fz_stext_block *block, mupdf::FzBuffer& res, mupdf::FzStextPage& p
last_char = 0;
for (line = block->u.t.first_line; line; line = line->next)
{
int break_line = 1;
for (ch = line->first_char; ch; ch = ch->next)
{
fz_rect chbbox = JM_char_bbox( line, ch);
if (mupdf::ll_fz_is_infinite_rect(rect) || JM_rects_overlap(rect, chbbox))
if (!ch->next && (line->flags & FZ_STEXT_LINE_FLAGS_JOINED)) {
break_line = 0;
}
else if (mupdf::ll_fz_is_infinite_rect(rect) || JM_rects_overlap(rect, chbbox))
{
last_char = ch->c;
JM_append_rune(res.m_internal, last_char);
}
}
if (last_char != 10 && last_char > 0)
if (!break_line)
{
}
else if (last_char != 10 && last_char > 0)
{
mupdf::ll_fz_append_string(res.m_internal, "\n");
last_char = 10;
Expand Down Expand Up @@ -3973,11 +3984,11 @@ PyObject *set_pixel(fz_pixmap* pm, int x, int y, PyObject *color)
throw std::range_error( MSG_PIXEL_OUTSIDE);
}
int n = pm->n;
if (!PySequence_Check(color) || PySequence_Size(color) != n) {
throw std::range_error(MSG_BAD_COLOR_SEQ);
}
int i, j;
unsigned char c[5];
if (!PySequence_Check(color) || PySequence_Size(color) != n || n > sizeof(c)) {
throw std::range_error(MSG_BAD_COLOR_SEQ);
}
for (j = 0; j < n; j++) {
if (JM_INT_ITEM(color, j, &i) == 1) {
throw std::range_error(MSG_BAD_COLOR_SEQ);
Expand Down Expand Up @@ -4013,14 +4024,22 @@ JM_new_buffer_from_stext_page(fz_stext_page *page)
for (block = page->first_block; block; block = block->next) {
if (block->type == FZ_STEXT_BLOCK_TEXT) {
for (line = block->u.t.first_line; line; line = line->next) {
int break_line = 1;
for (ch = line->first_char; ch; ch = ch->next) {
if (!JM_rects_overlap(rect, JM_char_bbox(line, ch)) &&
!fz_is_infinite_rect(rect)) {
continue;
}
fz_append_rune(ctx, buf, ch->c);
if (!ch->next && (line->flags & FZ_STEXT_LINE_FLAGS_JOINED)) {
break_line = 0;
}
else {
fz_append_rune(ctx, buf, ch->c);
}
}
if (break_line) {
fz_append_byte(ctx, buf, '\n');
}
fz_append_byte(ctx, buf, '\n');
}
fz_append_byte(ctx, buf, '\n');
}
Expand Down Expand Up @@ -4261,8 +4280,9 @@ try_new_match:
haystack += fz_chartorune(&c, haystack);
next_char:;
}
assert(*haystack == '\n');
++haystack;
if (*haystack == '\n') {
++haystack;
}
}
assert(*haystack == '\n');
++haystack;
Expand Down Expand Up @@ -4347,7 +4367,10 @@ PyObject* ll_JM_color_count(fz_pixmap *pm, PyObject *clip)
unsigned char* s = pm->samples + stride * (irect.y0 - pm->y) + n * (irect.x0 - pm->x);
// Cache previous pixel.
char oldpix[10];
assert(n <= sizeof(oldpix));
if (n > sizeof(oldpix))
{
throw std::range_error(MSG_PIXEL_OUTSIDE);
}
memcpy(oldpix, s, n);
long cnt = 0;
for (size_t i = 0; i < height; i++)
Expand Down
Binary file added tests/resources/test_4994.pdf
Binary file not shown.
18 changes: 18 additions & 0 deletions tests/test_annots.py
Original file line number Diff line number Diff line change
Expand Up @@ -794,3 +794,21 @@ def test_4936():
drawings = page.get_drawings()
print(f'{len(drawings)=}')
assert len(drawings) == 0


def test_5112():
print()
with pymupdf.open() as document:
page = document.new_page()
rect = pymupdf.Rect(50, 50, 200, 150)
callout = [(10, 10)] * 100
try:
print(f'test_5112(): calling page.add_freetext_annot().', flush=1)
e = page.add_freetext_annot(rect, "test", callout=callout)
except Exception as e:
print(f'Received exception: {e}')
assert isinstance(e, RuntimeError)
assert str(e) == 'bad seq of points'
else:
assert 0, f'Expected exception from page.add_freetext_annot().'

23 changes: 23 additions & 0 deletions tests/test_textextract.py
Original file line number Diff line number Diff line change
Expand Up @@ -948,3 +948,26 @@ def test_4503():

assert strikeout, f'Expected bit 0 (FZ_STEXT_STRIKEOUT) to be set in {span_0["char_flags"]=:#x}.'
assert text_0 == 'the right to request the state to review and, if appropriate,'


def test_4994():
print()
print(f'{pymupdf.pymupdf_version=}.')
print(f'{pymupdf.pymupdf_version_tuple=}.')
sys.stdout.flush()
path = os.path.normpath(f'{__file__}/../../tests/resources/test_4994.pdf')
with pymupdf.open(path) as document:
for page in document:
text = page.get_text()
print(f'test_4994(): {page.get_text()=}')
print(f'test_4994(): {page.get_text(flags=pymupdf.TEXTFLAGS_TEXT | pymupdf.TEXT_DEHYPHENATE)=}')
print(f'test_4994(): {page.get_text(flags=pymupdf.TEXT_DEHYPHENATE)=}')
sys.stdout.flush()
search_results = page.search_for('climate')
print(f'test_4994(): {search_results=}')
print(f'test_4994(): {len(search_results)=}')
print(f'test_4994(): {search_results=}')
sys.stdout.flush()
assert len(search_results) == 2
#assert text == 'planet-warming gas driving climate change.'
sys.stdout.flush()
Loading