Skip to content

Commit 312e4a7

Browse files
src/: optimise Pixmap.color_count().
Addresses #4336.
1 parent d52351a commit 312e4a7

File tree

2 files changed

+62
-0
lines changed

2 files changed

+62
-0
lines changed

src/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14847,6 +14847,9 @@ def JM_color_FromSequence(color):
1484714847

1484814848

1484914849
def JM_color_count( pm, clip):
14850+
if g_use_extra:
14851+
return extra.ll_JM_color_count(pm.m_internal, clip)
14852+
1485014853
rc = dict()
1485114854
cnt = 0
1485214855
irect = mupdf.fz_pixmap_bbox( pm)

src/extra.i

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4095,6 +4095,63 @@ void pixmap_copy( fz_pixmap* pm, const fz_pixmap* src, int n)
40954095
}
40964096

40974097

4098+
PyObject* ll_JM_color_count(fz_pixmap *pm, PyObject *clip)
4099+
{
4100+
fz_context* ctx = mupdf::internal_context_get();
4101+
PyObject* rc = PyDict_New();
4102+
fz_irect irect = fz_pixmap_bbox(ctx, pm);
4103+
irect = fz_intersect_irect(irect, fz_round_rect(JM_rect_from_py(clip)));
4104+
if (fz_is_empty_irect(irect))
4105+
{
4106+
return rc;
4107+
}
4108+
size_t stride = pm->stride;
4109+
size_t width = irect.x1 - irect.x0;
4110+
size_t height = irect.y1 - irect.y0;
4111+
size_t n = (size_t) pm->n;
4112+
size_t substride = width * n;
4113+
unsigned char* s = pm->samples + stride * (irect.y0 - pm->y) + n * (irect.x0 - pm->x);
4114+
// Cache previous pixel.
4115+
char oldpix[10];
4116+
assert(n < = size(oldpix));
4117+
memcpy(oldpix, s, n);
4118+
long cnt = 0;
4119+
for (size_t i = 0; i < height; i++)
4120+
{
4121+
for (size_t j = 0; j < substride; j += n)
4122+
{
4123+
const char* newpix = (const char*) s + j;
4124+
if (memcmp(oldpix, newpix, n))
4125+
{
4126+
/* Pixel differs from previous pixel, so update results with
4127+
last run of pixels. We get a PyObject representation of pixel
4128+
so we can look up in Python dict <rc>. */
4129+
PyObject* pixel = PyBytes_FromStringAndSize(&oldpix[0], n);
4130+
PyObject* c = PyDict_GetItem(rc, pixel);
4131+
if (c) cnt += PyLong_AsLong(c);
4132+
DICT_SETITEM_DROP(rc, pixel, PyLong_FromLong(cnt));
4133+
Py_DECREF(pixel);
4134+
/* Start next run of identical pixels. */
4135+
cnt = 1;
4136+
memcpy(oldpix, newpix, n);
4137+
}
4138+
else
4139+
{
4140+
cnt += 1;
4141+
}
4142+
}
4143+
s += stride;
4144+
}
4145+
/* Update results with last pixel. */
4146+
PyObject* pixel = PyBytes_FromStringAndSize(&oldpix[0], n);
4147+
PyObject* c = PyDict_GetItem(rc, pixel);
4148+
if (c) cnt += PyLong_AsLong(c);
4149+
DICT_SETITEM_DROP(rc, pixel, PyLong_FromLong(cnt));
4150+
Py_DECREF(pixel);
4151+
PyErr_Clear();
4152+
return rc;
4153+
}
4154+
40984155
%}
40994156

41004157
/* Declarations for functions defined above. */
@@ -4224,3 +4281,5 @@ src->n must be -1, 0 or +1. If -1, <src> must have alpha and <pm> must not have
42244281
alpha, and we copy the non-alpha bytes. If +1 <src> must not have alpha and
42254282
<pm> must have alpha and we set <pm>'s alpha bytes all to 255.*/
42264283
void pixmap_copy(fz_pixmap* pm, const fz_pixmap* src, int n);
4284+
4285+
PyObject* ll_JM_color_count(fz_pixmap *pm, PyObject *clip);

0 commit comments

Comments
 (0)