Skip to content

Commit 423e059

Browse files
committed
Detect image masks in TextPage output
1 parent dd828bd commit 423e059

File tree

5 files changed

+68
-14
lines changed

5 files changed

+68
-14
lines changed

src/__init__.py

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12585,6 +12585,11 @@ def extractIMGINFO(self, hashes=0):
1258512585
continue
1258612586
img = block.i_image()
1258712587
img_size = 0
12588+
mask = img.mask()
12589+
if mask.m_internal:
12590+
has_mask = True
12591+
else:
12592+
has_mask = False
1258812593
compr_buff = mupdf.fz_compressed_image_buffer(img)
1258912594
if compr_buff.m_internal:
1259012595
img_size = compr_buff.fz_compressed_buffer_size()
@@ -12600,19 +12605,20 @@ def extractIMGINFO(self, hashes=0):
1260012605
img_size = img.w() * img.h() * img.n()
1260112606
cs = mupdf.FzColorspace(mupdf.ll_fz_keep_colorspace(img.m_internal.colorspace))
1260212607
block_dict = dict()
12603-
block_dict[ dictkey_number] = block_n
12604-
block_dict[ dictkey_bbox] = JM_py_from_rect(block.m_internal.bbox)
12605-
block_dict[ dictkey_matrix] = JM_py_from_matrix(block.i_transform())
12606-
block_dict[ dictkey_width] = img.w()
12607-
block_dict[ dictkey_height] = img.h()
12608-
block_dict[ dictkey_colorspace] = mupdf.fz_colorspace_n(cs)
12609-
block_dict[ dictkey_cs_name] = mupdf.fz_colorspace_name(cs)
12610-
block_dict[ dictkey_xres] = img.xres()
12611-
block_dict[ dictkey_yres] = img.yres()
12612-
block_dict[ dictkey_bpc] = img.bpc()
12613-
block_dict[ dictkey_size] = img_size
12608+
block_dict[dictkey_number] = block_n
12609+
block_dict[dictkey_bbox] = JM_py_from_rect(block.m_internal.bbox)
12610+
block_dict[dictkey_matrix] = JM_py_from_matrix(block.i_transform())
12611+
block_dict[dictkey_width] = img.w()
12612+
block_dict[dictkey_height] = img.h()
12613+
block_dict[dictkey_colorspace] = mupdf.fz_colorspace_n(cs)
12614+
block_dict[dictkey_cs_name] = mupdf.fz_colorspace_name(cs)
12615+
block_dict[dictkey_xres] = img.xres()
12616+
block_dict[dictkey_yres] = img.yres()
12617+
block_dict[dictkey_bpc] = img.bpc()
12618+
block_dict[dictkey_size] = img_size
1261412619
if hashes:
12615-
block_dict[ "digest"] = digest
12620+
block_dict["digest"] = digest
12621+
block_dict["has-mask"] = has_mask
1261612622
rc.append(block_dict)
1261712623
return rc
1261812624

@@ -16514,6 +16520,13 @@ def _make_image_dict(img, img_dict):
1651416520
def JM_make_image_block(block, block_dict):
1651516521
img = block.i_image()
1651616522
_make_image_dict(img, block_dict)
16523+
# if the image has a mask, store it as a PNG buffer
16524+
mask = img.mask()
16525+
if mask.m_internal:
16526+
buff = mask.fz_new_buffer_from_image_as_png(mupdf.FzColorParams(mupdf.fz_default_color_params))
16527+
block_dict["mask"] = buff.fz_buffer_extract()
16528+
else:
16529+
block_dict["mask"] = None
1651716530
block_dict[dictkey_matrix] = JM_py_from_matrix(block.i_transform())
1651816531

1651916532

src/extra.i

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3504,10 +3504,11 @@ void JM_make_image_block(fz_stext_block *block, PyObject *block_dict)
35043504
{
35053505
fz_context* ctx = mupdf::internal_context_get();
35063506
fz_image *image = block->u.i.image;
3507-
fz_buffer *buf = NULL, *freebuf = NULL;
3507+
fz_buffer *buf = NULL, *freebuf = NULL, *mask_buf = NULL;
35083508
fz_compressed_buffer *buffer = fz_compressed_image_buffer(ctx, image);
35093509
fz_var(buf);
35103510
fz_var(freebuf);
3511+
fz_var(mask_buf);
35113512
int n = fz_colorspace_n(ctx, image->colorspace);
35123513
int w = image->w;
35133514
int h = image->h;
@@ -3521,6 +3522,8 @@ void JM_make_image_block(fz_stext_block *block, PyObject *block_dict)
35213522
type = FZ_IMAGE_UNKNOWN;
35223523
PyObject *bytes = NULL;
35233524
fz_var(bytes);
3525+
PyObject *mask_bytes = NULL;
3526+
fz_var(mask_bytes);
35243527
fz_try(ctx) {
35253528
if (!buffer || type == FZ_IMAGE_UNKNOWN)
35263529
{
@@ -3536,6 +3539,12 @@ void JM_make_image_block(fz_stext_block *block, PyObject *block_dict)
35363539
buf = buffer->buffer;
35373540
}
35383541
bytes = JM_BinFromBuffer(buf);
3542+
if (image->mask) {
3543+
mask_buf = fz_new_buffer_from_image_as_png(ctx, image->mask, fz_default_color_params);
3544+
mask_bytes = JM_BinFromBuffer(mask_buf);
3545+
} else {
3546+
mask_bytes = Py_BuildValue("s", NULL);
3547+
}
35393548
}
35403549
fz_always(ctx) {
35413550
if (!bytes)
@@ -3559,7 +3568,8 @@ void JM_make_image_block(fz_stext_block *block, PyObject *block_dict)
35593568
DICT_SETITEM_DROP(block_dict, dictkey_size,
35603569
Py_BuildValue("n", PyBytes_Size(bytes)));
35613570
DICT_SETITEM_DROP(block_dict, dictkey_image, bytes);
3562-
3571+
DICT_SETITEMSTR_DROP(block_dict, "mask", mask_bytes);
3572+
fz_drop_buffer(ctx, mask_buf);
35633573
fz_drop_buffer(ctx, freebuf);
35643574
}
35653575
fz_catch(ctx) {;}

tests/resources/img-regular.pdf

20.7 KB
Binary file not shown.

tests/resources/img-transparent.pdf

22.8 KB
Binary file not shown.

tests/test_imagemasks.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
"""
2+
Confirm image mask detection in TextPage extractions.
3+
"""
4+
5+
import os
6+
7+
import pymupdf
8+
9+
scriptdir = os.path.abspath(os.path.dirname(__file__))
10+
filename1 = os.path.join(scriptdir, "resources", "img-regular.pdf")
11+
filename2 = os.path.join(scriptdir, "resources", "img-transparent.pdf")
12+
13+
14+
def test_imagemask1():
15+
doc = pymupdf.open(filename1)
16+
page = doc[0]
17+
blocks = page.get_text("dict")["blocks"]
18+
img = blocks[0]
19+
assert img["mask"] is None
20+
img = page.get_image_info()[0]
21+
assert img["has-mask"] is False
22+
23+
24+
def test_imagemask2():
25+
doc = pymupdf.open(filename2)
26+
page = doc[0]
27+
blocks = page.get_text("dict")["blocks"]
28+
img = blocks[0]
29+
assert type(img["mask"]) is bytes
30+
img = page.get_image_info()[0]
31+
assert img["has-mask"] is True

0 commit comments

Comments
 (0)