PDF_REDACT_IMAGE_PIXELS,
};
+enum {
+ PDF_REDACT_LINE_ART_NONE,
+ PDF_REDACT_LINE_ART_REMOVE_IF_COVERED,
+ PDF_REDACT_LINE_ART_REMOVE_IF_TOUCHED
+};
+
typedef struct
{
int black_boxes;
int image_method;
+ int line_art;
} pdf_redact_options;
int pdf_redact_page(fz_context *ctx, pdf_document *doc, pdf_page *page, pdf_redact_options *opts);
int i;
int num_redact = 0;
- static pdf_redact_options redact_opts = { 1, PDF_REDACT_IMAGE_PIXELS };
+ static pdf_redact_options redact_opts = { 1, PDF_REDACT_IMAGE_PIXELS, PDF_REDACT_LINE_ART_REMOVE_IF_TOUCHED };
int search_valid;
if (pdf_has_redactions_doc != pdf)
if (ui_button_aux("Redact Page", num_redact == 0))
{
ui_select_annot(NULL);
- trace_action("page.applyRedactions(%s, %d);\n",
+ trace_action("page.applyRedactions(%s, %d, %d);\n",
redact_opts.black_boxes ? "true" : "false",
- redact_opts.image_method);
+ redact_opts.image_method,
+ redact_opts.line_art);
pdf_redact_page(ctx, pdf, page, &redact_opts);
trace_page_update();
load_page();
}
JNIEXPORT jboolean JNICALL
-FUN(PDFAnnotation_applyRedaction)(JNIEnv *env, jobject self, jboolean blackBoxes, jint imageMethod)
+FUN(PDFAnnotation_applyRedaction)(JNIEnv *env, jobject self, jboolean blackBoxes, jint imageMethod, jint lineArt)
{
fz_context *ctx = get_context(env);
pdf_annot *annot = from_PDFAnnotation_safe(env, self);
- pdf_redact_options opts = { blackBoxes, imageMethod };
+ pdf_redact_options opts = { blackBoxes, imageMethod, lineArt };
jboolean redacted = JNI_FALSE;
if (!ctx || !annot) return JNI_FALSE;
}
JNIEXPORT jboolean JNICALL
-FUN(PDFPage_applyRedactions)(JNIEnv *env, jobject self, jboolean blackBoxes, jint imageMethod)
+FUN(PDFPage_applyRedactions)(JNIEnv *env, jobject self, jboolean blackBoxes, jint imageMethod, jint lineArt)
{
fz_context *ctx = get_context(env);
pdf_page *page = from_PDFPage(env, self);
jboolean redacted = JNI_FALSE;
- pdf_redact_options opts = { blackBoxes, imageMethod };
+ pdf_redact_options opts = { blackBoxes, imageMethod, lineArt };
if (!ctx || !page) return JNI_FALSE;
/*
* Class: com_artifex_mupdf_fitz_PDFAnnotation
* Method: applyRedaction
- * Signature: (ZI)Z
+ * Signature: (ZII)Z
*/
JNIEXPORT jboolean JNICALL Java_com_artifex_mupdf_fitz_PDFAnnotation_applyRedaction
- (JNIEnv *, jobject, jboolean, jint);
+ (JNIEnv *, jobject, jboolean, jint, jint);
#ifdef __cplusplus
}
#define com_artifex_mupdf_fitz_PDFPage_REDACT_IMAGE_REMOVE 1L
#undef com_artifex_mupdf_fitz_PDFPage_REDACT_IMAGE_PIXELS
#define com_artifex_mupdf_fitz_PDFPage_REDACT_IMAGE_PIXELS 2L
+#undef com_artifex_mupdf_fitz_PDFPage_REDACT_LINEART_NONE
+#define com_artifex_mupdf_fitz_PDFPage_REDACT_LINEART_NONE 0L
+#undef com_artifex_mupdf_fitz_PDFPage_REDACT_LINEART_IF_TOUCHED
+#define com_artifex_mupdf_fitz_PDFPage_REDACT_LINEART_IF_TOUCHED 1L
+#undef com_artifex_mupdf_fitz_PDFPage_REDACT_LINEART_IF_COVERED
+#define com_artifex_mupdf_fitz_PDFPage_REDACT_LINEART_IF_COVERED 2L
/*
* Class: com_artifex_mupdf_fitz_PDFPage
* Method: getObject
/*
* Class: com_artifex_mupdf_fitz_PDFPage
* Method: applyRedactions
- * Signature: (ZI)Z
+ * Signature: (ZII)Z
*/
JNIEXPORT jboolean JNICALL Java_com_artifex_mupdf_fitz_PDFPage_applyRedactions
- (JNIEnv *, jobject, jboolean, jint);
+ (JNIEnv *, jobject, jboolean, jint, jint);
/*
* Class: com_artifex_mupdf_fitz_PDFPage
public native boolean getHiddenForEditing();
public native void setHiddenForEditing(boolean hidden);
- public native boolean applyRedaction(boolean blackBoxes, int imageMethod);
+ public boolean applyRedaction(boolean blackBoxes, int imageMethod)
+ {
+ return applyRedaction(blackBoxes, imageMethod, 0);
+ }
+
+ public native boolean applyRedaction(boolean blackBoxes, int imageMethod, int lineArt);
}
public static final int REDACT_IMAGE_REMOVE = 1;
public static final int REDACT_IMAGE_PIXELS = 2;
- public native boolean applyRedactions(boolean blackBoxes, int imageMethod);
+ public static final int REDACT_LINEART_NONE = 0;
+ public static final int REDACT_LINEART_IF_TOUCHED = 1;
+ public static final int REDACT_LINEART_IF_COVERED = 2;
+
+ public native boolean applyRedactions(boolean blackBoxes, int imageMethod, int lineArt);
public boolean applyRedactions() {
- return applyRedactions(true, REDACT_IMAGE_PIXELS);
+ return applyRedactions(true, REDACT_IMAGE_PIXELS, REDACT_LINEART_NONE);
+ }
+
+ public boolean applyRedactions(boolean blackBoxes, int imageMethod) {
+ return applyRedactions(blackBoxes, imageMethod, REDACT_LINEART_NONE);
}
public native boolean update();
pdf_filter_factory filter_list[2];
pdf_page *page;
pdf_annot *target; // NULL if all
+ int line_art;
};
static void
return fz_keep_image(ctx, image);
}
+/* Returns 0 if area does not intersect with any of our redactions.
+ * Returns 2 if area is completely included within one of our redactions.
+ * Returns 1 otherwise. */
static int
-rect_touches_redactions(fz_context *ctx, pdf_document *doc, pdf_page *page, fz_rect area, struct redact_filter_state *red)
+rect_touches_redactions(fz_context *ctx, fz_rect area, struct redact_filter_state *red)
{
pdf_annot *annot;
pdf_obj *qp;
fz_quad q;
- fz_rect r;
+ fz_rect r, s;
int i, n;
+ pdf_page *page = red->page;
+ pdf_document *doc = red->page->doc;
for (annot = pdf_first_annot(ctx, page); annot; annot = pdf_next_annot(ctx, annot))
{
{
q = pdf_to_quad(ctx, qp, i);
r = fz_rect_from_quad(q);
- r = fz_intersect_rect(r, area);
- if (!fz_is_empty_rect(r))
+ s = fz_intersect_rect(r, area);
+ if (!fz_is_empty_rect(s))
+ {
+ if (fz_contains_rect(r, area))
+ return 2;
return 1;
+ }
}
}
else
{
r = pdf_dict_get_rect(ctx, annot->obj, PDF_NAME(Rect));
- r = fz_intersect_rect(r, area);
- if (!fz_is_empty_rect(r))
+ s = fz_intersect_rect(r, area);
+ if (!fz_is_empty_rect(s))
+ {
+ if (fz_contains_rect(r, area))
+ return 2;
return 1;
+ }
}
}
}
}
static void
-pdf_redact_page_links(fz_context *ctx, pdf_document *doc, pdf_page *page, struct redact_filter_state *red)
+pdf_redact_page_links(fz_context *ctx, struct redact_filter_state *red)
{
pdf_obj *annots;
pdf_obj *link;
fz_rect area;
int k;
- annots = pdf_dict_get(ctx, page->obj, PDF_NAME(Annots));
+ annots = pdf_dict_get(ctx, red->page->obj, PDF_NAME(Annots));
k = 0;
while (k < pdf_array_len(ctx, annots))
{
if (pdf_dict_get(ctx, link, PDF_NAME(Subtype)) == PDF_NAME(Link))
{
area = pdf_dict_get_rect(ctx, link, PDF_NAME(Rect));
- if (rect_touches_redactions(ctx, doc, page, area, red))
+ if (rect_touches_redactions(ctx, area, red))
{
pdf_array_delete(ctx, annots, k);
continue;
}
static void
-pdf_redact_page_annotations(fz_context *ctx, pdf_document *doc, pdf_page *page, struct redact_filter_state *red)
+pdf_redact_page_annotations(fz_context *ctx, struct redact_filter_state *red)
{
pdf_annot *annot;
fz_rect area;
restart:
- for (annot = pdf_first_annot(ctx, page); annot; annot = pdf_next_annot(ctx, annot))
+ for (annot = pdf_first_annot(ctx, red->page); annot; annot = pdf_next_annot(ctx, annot))
{
if (pdf_annot_type(ctx, annot) == PDF_ANNOT_FREE_TEXT)
{
area = pdf_dict_get_rect(ctx, pdf_annot_obj(ctx, annot), PDF_NAME(Rect));
- if (rect_touches_redactions(ctx, doc, page, area, red))
+ if (rect_touches_redactions(ctx, area, red))
{
- pdf_delete_annot(ctx, page, annot);
+ pdf_delete_annot(ctx, red->page, annot);
goto restart;
}
}
}
}
+static int culler(fz_context *ctx, void *opaque, fz_rect bbox, fz_cull_type type)
+{
+ struct redact_filter_state *red = opaque;
+
+ switch (type)
+ {
+ case FZ_CULL_PATH_FILL:
+ case FZ_CULL_PATH_STROKE:
+ case FZ_CULL_PATH_FILL_STROKE:
+ if (red->line_art == PDF_REDACT_LINE_ART_REMOVE_IF_COVERED)
+ return (rect_touches_redactions(ctx, bbox, red) == 2);
+ else if (red->line_art == PDF_REDACT_LINE_ART_REMOVE_IF_TOUCHED)
+ return (rect_touches_redactions(ctx, bbox, red) != 0);
+ return 0;
+ default:
+ return 0;
+ }
+}
+
static
void init_redact_filter(fz_context *ctx, pdf_redact_options *redact_opts, struct redact_filter_state *red, pdf_page *page, pdf_annot *target)
{
int black_boxes = redact_opts ? redact_opts->black_boxes : 0;
int image_method = redact_opts ? redact_opts->image_method : PDF_REDACT_IMAGE_PIXELS;
+ int line_art = redact_opts ? redact_opts->line_art : PDF_REDACT_LINE_ART_NONE;
memset(&red->filter_opts, 0, sizeof red->filter_opts);
memset(&red->sanitize_opts, 0, sizeof red->sanitize_opts);
red->filter_opts.filters = red->filter_list;
if (black_boxes)
red->filter_opts.complete = pdf_redact_end_page;
+ red->line_art = line_art;
red->sanitize_opts.opaque = red;
red->sanitize_opts.text_filter = pdf_redact_text_filter;
red->sanitize_opts.image_filter = pdf_redact_image_filter_pixels;
if (image_method == PDF_REDACT_IMAGE_REMOVE)
red->sanitize_opts.image_filter = pdf_redact_image_filter_remove;
+ red->sanitize_opts.culler = culler;
red->filter_list[0].filter = pdf_new_sanitize_filter;
red->filter_list[0].options = &red->sanitize_opts;
}
static int
-pdf_apply_redaction_imp(fz_context *ctx, pdf_document *doc, pdf_page *page, pdf_annot *target, pdf_redact_options *redact_opts)
+pdf_apply_redaction_imp(fz_context *ctx, pdf_page *page, pdf_annot *target, pdf_redact_options *redact_opts)
{
pdf_annot *annot;
int has_redactions = 0;
struct redact_filter_state red;
+ pdf_document *doc = page->doc;
for (annot = pdf_first_annot(ctx, page); annot; annot = pdf_next_annot(ctx, annot)) {
if (target != NULL && target != annot)
fz_try(ctx)
{
pdf_filter_page_contents(ctx, doc, page, &red.filter_opts);
- pdf_redact_page_links(ctx, doc, page, &red);
- pdf_redact_page_annotations(ctx, doc, page, &red);
+ pdf_redact_page_links(ctx, &red);
+ pdf_redact_page_annotations(ctx, &red);
annot = pdf_first_annot(ctx, page);
while (annot)
int
pdf_redact_page(fz_context *ctx, pdf_document *doc, pdf_page *page, pdf_redact_options *redact_opts)
{
- return pdf_apply_redaction_imp(ctx, doc, page, NULL, redact_opts);
+ if (page == NULL || page->doc != doc)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Can't redact a page not from the doc");
+ return pdf_apply_redaction_imp(ctx, page, NULL, redact_opts);
}
int
pdf_apply_redaction(fz_context *ctx, pdf_annot *annot, pdf_redact_options *redact_opts)
{
- return pdf_apply_redaction_imp(ctx, annot->page->doc, annot->page, annot, redact_opts);
+ return pdf_apply_redaction_imp(ctx, annot->page, annot, redact_opts);
}
pdf_sanitize_processor *p = (pdf_sanitize_processor *)arg;
if (p->chain->op_re)
- p->chain->op_re(ctx, p->chain, x1, y1, x2, y2);
+ p->chain->op_re(ctx, p->chain, x1, y1, x2-x1, y2-y1);
}
typedef struct
cull_replay_rectto
};
fz_rect r;
+ const fz_stroke_state *st;
if (sd->segment == NULL)
return;
- r = fz_bound_path(ctx, sd->segment, (sd->type == FZ_CULL_PATH_STROKE || sd->type == FZ_CULL_PATH_FILL_STROKE) ? &sd->sstate : NULL, sd->ctm);
+ st = (sd->type == FZ_CULL_PATH_STROKE || sd->type == FZ_CULL_PATH_FILL_STROKE) ? &sd->sstate : NULL;
+ r = fz_bound_path(ctx, sd->segment, st, sd->ctm);
- if (sd->p->options->culler(ctx, sd->p->options->opaque, r, sd->type))
+ if (sd->p->options->culler && sd->p->options->culler(ctx, sd->p->options->opaque, r, sd->type))
{
/* This segment can be skipped */
}
parent_diff = pdf_objcmp(ctx, parent, expected_parent);
prev_diff = pdf_objcmp(ctx, prev, expected_prev);
- last_diff = next == NULL && pdf_objcmp(ctx, last, dict);
+ last_diff = next == NULL && pdf_objcmp_resolve(ctx, last, dict);
if (fixed == NULL)
{
{
fz_context *ctx = js_getcontext(J);
pdf_page *page = js_touserdata(J, 0, "pdf_page");
- pdf_redact_options opts = { 1, PDF_REDACT_IMAGE_PIXELS };
+ pdf_redact_options opts = { 1, PDF_REDACT_IMAGE_PIXELS, 0 };
if (js_isdefined(J, 1)) opts.black_boxes = js_toboolean(J, 1);
if (js_isdefined(J, 2)) opts.image_method = js_tointeger(J, 2);
+ if (js_isdefined(J, 3)) opts.line_art = js_tointeger(J, 3);
fz_try(ctx)
pdf_redact_page(ctx, page->doc, page, &opts);
fz_catch(ctx)
{
fz_context *ctx = js_getcontext(J);
pdf_annot *annot = ffi_toannot(J, 0);
- pdf_redact_options opts = { 1, PDF_REDACT_IMAGE_PIXELS };
+ pdf_redact_options opts = { 1, PDF_REDACT_IMAGE_PIXELS, 0 };
if (js_isdefined(J, 1)) opts.black_boxes = js_toboolean(J, 1);
if (js_isdefined(J, 2)) opts.image_method = js_tointeger(J, 2);
+ if (js_isdefined(J, 3)) opts.line_art = js_tointeger(J, 3);
fz_try(ctx)
pdf_apply_redaction(ctx, annot, &opts);
fz_catch(ctx)
jsB_propfun(J, "PDFPage.createAnnotation", ffi_PDFPage_createAnnotation, 1);
jsB_propfun(J, "PDFPage.deleteAnnotation", ffi_PDFPage_deleteAnnotation, 1);
jsB_propfun(J, "PDFPage.update", ffi_PDFPage_update, 0);
- jsB_propfun(J, "PDFPage.applyRedactions", ffi_PDFPage_applyRedactions, 2);
+ jsB_propfun(J, "PDFPage.applyRedactions", ffi_PDFPage_applyRedactions, 3);
jsB_propfun(J, "PDFPage.process", ffi_PDFPage_process, 1);
jsB_propfun(J, "PDFPage.toPixmap", ffi_PDFPage_toPixmap, 6);
jsB_propfun(J, "PDFPage.getTransform", ffi_PDFPage_getTransform, 0);
jsB_propfun(J, "PDFAnnotation.getIsOpen", ffi_PDFAnnotation_getIsOpen, 0);
jsB_propfun(J, "PDFAnnotation.setIsOpen", ffi_PDFAnnotation_setIsOpen, 1);
- jsB_propfun(J, "PDFAnnotation.applyRedaction", ffi_PDFAnnotation_applyRedaction, 2);
+ jsB_propfun(J, "PDFAnnotation.applyRedaction", ffi_PDFAnnotation_applyRedaction, 3);
jsB_propfun(J, "PDFAnnotation.process", ffi_PDFAnnotation_process, 1);
jsB_propfun(J, "PDFAnnotation.getHiddenForEditing", ffi_PDFAnnotation_getHiddenForEditing, 0);