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
1 change: 1 addition & 0 deletions drawcontext.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ typedef struct DrawContext {
double gamma;
int offset_x;
int offset_y;
int isolate_smask;
} DrawContext;

#endif
Expand Down
1 change: 1 addition & 0 deletions ffi-cdecl/wrap-mupdf_cdecl.c
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ cdecl_func(fz_device_bgr)
/* device, rendering */
cdecl_func(mupdf_new_draw_device)
cdecl_func(mupdf_new_bbox_device)
cdecl_func(mupdf_new_isolated_smask_device)
cdecl_func(mupdf_run_page)
cdecl_func(fz_close_device)
cdecl_func(fz_drop_device)
Expand Down
7 changes: 5 additions & 2 deletions ffi/drawcontext.lua
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ typedef struct DrawContext {
double gamma;
int offset_x;
int offset_y;
int isolate_smask;
} DrawContext;
]]

Expand All @@ -30,11 +31,13 @@ end
function DC_mt.__index:getOffset() return self.offset_x, self.offset_y end
function DC_mt.__index:setGamma(gamma) self.gamma = gamma end
function DC_mt.__index:getGamma() return self.gamma end
function DC_mt.__index:setIsolateSMask(isolate_smask) self.isolate_smask = isolate_smask end
function DC_mt.__index:getIsolateSMask() return self.isolate_smask end

local dctype = ffi.metatype("DrawContext", DC_mt)

function DC.new(rotate, zoom, x, y, gamma)
return dctype(rotate or 0, zoom or 1.0, gamma or -1.0, x or 0, y or 0)
function DC.new(rotate, zoom, x, y, gamma, isolate_smask)
return dctype(rotate or 0, zoom or 1.0, gamma or -1.0, x or 0, y or 0, isolate_smask or 0)
end

return DC
21 changes: 17 additions & 4 deletions ffi/mupdf.lua
Original file line number Diff line number Diff line change
Expand Up @@ -670,15 +670,28 @@ function page_mt.__index:getPageLinks()
return links
end

local function run_page(page, pixmap, ctm)
local function run_page(page, pixmap, ctm, isolate_smask)
M.fz_clear_pixmap_with_value(page.ctx, pixmap, 0xff)

local dev = W.mupdf_new_draw_device(page.ctx, nil, pixmap)
if dev == nil then merror(page.ctx, "cannot create draw device") end

local ok = W.mupdf_run_page(page.ctx, page.page, dev, ctm, nil)
local ok = false
if isolate_smask then
local smask_dev = W.mupdf_new_isolated_smask_device(page.ctx, dev)
if smask_dev then
ok = W.mupdf_run_page(page.ctx, page.page, smask_dev, ctm, nil)
M.fz_close_device(page.ctx, smask_dev)
M.fz_drop_device(page.ctx, smask_dev)
end
end
if not ok then
ok = W.mupdf_run_page(page.ctx, page.page, dev, ctm, nil)
end

M.fz_close_device(page.ctx, dev)
M.fz_drop_device(page.ctx, dev)

if ok == nil then merror(page.ctx, "could not run page") end
end
--[[
Expand Down Expand Up @@ -717,7 +730,7 @@ function page_mt.__index:draw_new(draw_context, width, height, offset_x, offset_
self.ctx, colorspace, bbox, nil, self.doc.color and 1 or 0, ffi.cast("unsigned char*", bb.data))
if pix == nil then merror(self.ctx, "cannot allocate pixmap") end

run_page(self, pix, ctm)
run_page(self, pix, ctm, draw_context.isolate_smask == 1)

if draw_context.gamma >= 0.0 then
M.fz_gamma_pixmap(self.ctx, pix, draw_context.gamma)
Expand Down Expand Up @@ -1087,7 +1100,7 @@ local function render_for_kopt(bmp, page, scale, bounds)
local pix = W.mupdf_new_pixmap_with_bbox(page.ctx, colorspace, bbox, nil, 1)
if pix == nil then merror(page.ctx, "could not allocate pixmap") end

run_page(page, pix, ctm)
run_page(page, pix, ctm, false)

k2pdfopt.bmp_init(bmp)

Expand Down
1 change: 1 addition & 0 deletions ffi/mupdf_h.lua
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ fz_colorspace *fz_device_rgb(fz_context *);
fz_colorspace *fz_device_bgr(fz_context *);
fz_device *mupdf_new_draw_device(fz_context *, const fz_matrix *, fz_pixmap *);
fz_device *mupdf_new_bbox_device(fz_context *, fz_rect *);
fz_device *mupdf_new_isolated_smask_device(fz_context *, fz_device *);
void *mupdf_run_page(fz_context *, fz_page *, fz_device *, const fz_matrix *, fz_cookie *);
void fz_close_device(fz_context *, fz_device *);
void fz_drop_device(fz_context *, fz_device *);
Expand Down
23 changes: 23 additions & 0 deletions wrap-mupdf.c
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,29 @@ fz_rect *mupdf_fz_bound_page(fz_context *ctx, fz_page *page, fz_rect *r) {
return r;
}

typedef struct
{
fz_device super;
fz_device* default_device;
} isolated_smask_device;

static void smask_fill_image(fz_context* ctx, fz_device* dev, fz_image* img, fz_matrix ctm, float alpha, fz_color_params color_params)
{
if (img->mask) {
isolated_smask_device* smask_dev = (isolated_smask_device*)dev;
float black[1] = { 0.f };
fz_fill_image_mask(ctx, smask_dev->default_device, img->mask, ctm, fz_device_gray(ctx), black, alpha, color_params);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it correct that fz_device_gray doesn't need any cleanup?

@kerivin kerivin May 18, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like it.
Here's an example from the official documentation:

float cmyk[100][4] = { {1,0,0,0}, ...
float rgb[100][3];
fz_color_converter cc;
int i;

fz_find_color_converter(ctx,
	&cc,
	fz_device_cmyk(ctx),
	fz_device_rgb(ctx),
	NULL,
	fz_default_color_params(ctx)
);
for (i = 0; i < 100; ++i)
	cc.convert(ctx, &cc, cmyk[i], rgb[i]);
fz_drop_color_converter(ctx, &cc);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/**
	Retrieve global default colorspaces.

	These return borrowed references that should not be dropped,
	unless they are kept first.
*/
fz_colorspace *fz_device_gray(fz_context *ctx);
fz_colorspace *fz_device_rgb(fz_context *ctx);
fz_colorspace *fz_device_bgr(fz_context *ctx);
fz_colorspace *fz_device_cmyk(fz_context *ctx);
fz_colorspace *fz_device_lab(fz_context *ctx);

}
}

fz_device *fz_new_isolated_smask_device(fz_context* ctx, fz_device* dev)
{
isolated_smask_device* smask_dev = fz_new_derived_device(ctx, isolated_smask_device);
smask_dev->default_device = dev;
smask_dev->super.fill_image = smask_fill_image;
return (fz_device*)smask_dev;
}

/* wrappers for functions that throw exceptions mupdf-style (setjmp/longjmp) */

#define MUPDF_DO_WRAP
Expand Down
3 changes: 3 additions & 0 deletions wrap-mupdf.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,9 @@ MUPDF_WRAP(mupdf_new_bbox_device, fz_device*, NULL,
MUPDF_WRAP(mupdf_new_draw_device, fz_device*, NULL,
ret = fz_new_draw_device(ctx, transform ? *transform : fz_identity, dest),
const fz_matrix *transform, fz_pixmap *dest)
MUPDF_WRAP(mupdf_new_isolated_smask_device, fz_device*, NULL,
ret = fz_new_isolated_smask_device(ctx, dev),
fz_device *dev)
MUPDF_WRAP(mupdf_run_page, void*, NULL,
{ fz_run_page(ctx, page, dev, *transform, cookie); ret = (void*) -1; },
fz_page *page, fz_device *dev, const fz_matrix *transform, fz_cookie *cookie)
Expand Down