glib/demo/annots.c | 171 ++++++++++++++++++++- glib/poppler-annot.cc | 288 ++++++++++++++++++++++++++++++++++++ glib/poppler-annot.h | 35 ++++ glib/poppler-page.cc | 3 glib/poppler-private.h | 2 glib/poppler.h | 1 glib/reference/poppler-sections.txt | 10 + glib/reference/poppler.types | 1 8 files changed, 507 insertions(+), 4 deletions(-)
New commits: commit a0e4ff30be462cae010d22d291ab282f5d86a5e3 Author: Nelson Benítez León <nbenit...@gmail.com> Date: Wed May 11 21:07:30 2022 -0400 glib: add support for stamp annotation Creates new PopplerAnnotStamp type with the following public api: PopplerAnnot *poppler_annot_stamp_new(PopplerDocument *doc, PopplerRectangle *rect); PopplerAnnotStampIcon poppler_annot_stamp_get_icon(PopplerAnnotStamp *poppler_annot); void poppler_annot_stamp_set_icon(PopplerAnnotStamp *poppler_annot, PopplerAnnotStampIcon icon); gboolean poppler_annot_stamp_set_custom_image(PopplerAnnotStamp *poppler_annot, cairo_surface_t *image, GError **error); Updates poppler-glib-demo to test PopplerAnnotStamp including the custom image support. diff --git a/glib/demo/annots.c b/glib/demo/annots.c index 799fe434..645a7210 100644 --- a/glib/demo/annots.c +++ b/glib/demo/annots.c @@ -22,6 +22,8 @@ #include "annots.h" #include "utils.h" +#define STAMP_CUSTOM_IMAGE "Custom image" + enum { ANNOTS_TYPE_COLUMN, @@ -47,10 +49,26 @@ typedef struct } Annotations; static const Annotations supported_annots[] = { - { POPPLER_ANNOT_TEXT, "Text" }, { POPPLER_ANNOT_LINE, "Line" }, { POPPLER_ANNOT_SQUARE, "Square" }, { POPPLER_ANNOT_CIRCLE, "Circle" }, - { POPPLER_ANNOT_HIGHLIGHT, "Highlight" }, { POPPLER_ANNOT_UNDERLINE, "Underline" }, { POPPLER_ANNOT_SQUIGGLY, "Squiggly" }, { POPPLER_ANNOT_STRIKE_OUT, "Strike Out" }, + { POPPLER_ANNOT_TEXT, "Text" }, { POPPLER_ANNOT_LINE, "Line" }, { POPPLER_ANNOT_SQUARE, "Square" }, { POPPLER_ANNOT_CIRCLE, "Circle" }, { POPPLER_ANNOT_HIGHLIGHT, "Highlight" }, + { POPPLER_ANNOT_UNDERLINE, "Underline" }, { POPPLER_ANNOT_SQUIGGLY, "Squiggly" }, { POPPLER_ANNOT_STRIKE_OUT, "Strike Out" }, { POPPLER_ANNOT_STAMP, "Stamp" }, }; +static const char *stamp_types[] = { [POPPLER_ANNOT_STAMP_ICON_UNKNOWN] = "Unknown", + [POPPLER_ANNOT_STAMP_ICON_APPROVED] = "APPROVED", + [POPPLER_ANNOT_STAMP_ICON_AS_IS] = "AS_IS", + [POPPLER_ANNOT_STAMP_ICON_CONFIDENTIAL] = "CONFIDENTIAL", + [POPPLER_ANNOT_STAMP_ICON_FINAL] = "FINAL", + [POPPLER_ANNOT_STAMP_ICON_EXPERIMENTAL] = "EXPERIMENTAL", + [POPPLER_ANNOT_STAMP_ICON_EXPIRED] = "EXPIRED", + [POPPLER_ANNOT_STAMP_ICON_NOT_APPROVED] = "NOT_APPROVED", + [POPPLER_ANNOT_STAMP_ICON_NOT_FOR_PUBLIC_RELEASE] = "NOT_FOR_PUBLIC_RELEASE", + [POPPLER_ANNOT_STAMP_ICON_SOLD] = "SOLD", + [POPPLER_ANNOT_STAMP_ICON_DEPARTMENTAL] = "DEPARTMENTAL", + [POPPLER_ANNOT_STAMP_ICON_FOR_COMMENT] = "FOR_COMMENT", + [POPPLER_ANNOT_STAMP_ICON_FOR_PUBLIC_RELEASE] = "FOR_PUBLIC_RELEASE", + [POPPLER_ANNOT_STAMP_ICON_TOP_SECRET] = "TOP_SECRET", + [POPPLER_ANNOT_STAMP_ICON_NONE] = "None" }; + typedef enum { MODE_NORMAL, /* Regular use as pointer in the page */ @@ -72,10 +90,12 @@ typedef struct GtkWidget *timer_label; GtkWidget *remove_button; GtkWidget *type_selector; + GtkWidget *stamp_selector; GtkWidget *main_box; gint num_page; gint annot_type; + char *custom_image_filename; ModeType mode; cairo_surface_t *surface; @@ -460,6 +480,14 @@ static void pgd_annot_view_set_annot_free_text(GtkWidget *table, PopplerAnnotFre g_free(text); } +static void pgd_annot_view_set_annot_stamp(GtkWidget *table, PopplerAnnotStamp *annot, gint *row) +{ + PopplerAnnotStampIcon icon; + + icon = poppler_annot_stamp_get_icon(annot); + pgd_table_add_property(GTK_GRID(table), "<b>Icon Name:</b>", stamp_types[icon], row); +} + static void pgd_annots_file_attachment_save_dialog_response(GtkFileChooser *file_chooser, gint response, PopplerAttachment *attachment) { gchar *filename; @@ -614,6 +642,9 @@ static void pgd_annot_view_set_annot(PgdAnnotsDemo *demo, PopplerAnnot *annot) case POPPLER_ANNOT_SCREEN: pgd_annot_view_set_annot_screen(table, POPPLER_ANNOT_SCREEN(annot), &row); break; + case POPPLER_ANNOT_STAMP: + pgd_annot_view_set_annot_stamp(table, POPPLER_ANNOT_STAMP(annot), &row); + break; default: break; } @@ -791,6 +822,19 @@ static GArray *pgd_annots_create_quads_array_for_rectangle(PopplerRectangle *rec return quads_array; } +static PopplerAnnotStampIcon get_icon_from_stamp_text(gchar *icon_text) +{ + int i; + + for (i = 1; i < G_N_ELEMENTS(stamp_types) - 1; i++) { + if (strcmp(stamp_types[i], icon_text) == 0) { + return (PopplerAnnotStampIcon)i; + } + } + + return POPPLER_ANNOT_STAMP_ICON_UNKNOWN; +} + static void pgd_annots_add_annot(PgdAnnotsDemo *demo) { PopplerRectangle rect; @@ -860,13 +904,35 @@ static void pgd_annots_add_annot(PgdAnnotsDemo *demo) annot = poppler_annot_text_markup_new_strikeout(demo->doc, &rect, quads_array); g_array_free(quads_array, TRUE); } break; + case POPPLER_ANNOT_STAMP: { + annot = poppler_annot_stamp_new(demo->doc, &rect); + gchar *stamp_type = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(demo->stamp_selector)); + GError *error = NULL; + + if (strcmp(stamp_type, STAMP_CUSTOM_IMAGE) == 0 && demo->custom_image_filename) { + cairo_surface_t *img = cairo_image_surface_create_from_png(demo->custom_image_filename); + if (cairo_surface_status(img) == CAIRO_STATUS_SUCCESS) { + poppler_annot_stamp_set_custom_image(POPPLER_ANNOT_STAMP(annot), img, &error); + if (error) { + g_warning("%s", error->message); + g_error_free(error); + } + } + cairo_surface_destroy(img); + } else { + poppler_annot_stamp_set_icon(POPPLER_ANNOT_STAMP(annot), get_icon_from_stamp_text(stamp_type)); + } + g_free(stamp_type); + } break; default: g_assert_not_reached(); } demo->active_annot = annot; - poppler_annot_set_color(annot, &color); + if (demo->annot_type != POPPLER_ANNOT_STAMP) { + poppler_annot_set_color(annot, &color); + } poppler_page_add_annot(demo->page, annot); pgd_annots_add_annot_to_model(demo, annot, rect, TRUE); g_object_unref(annot); @@ -1056,6 +1122,83 @@ static gboolean pgd_annots_drawing_area_button_press(GtkWidget *area, GdkEventBu return TRUE; } +static void choose_custom_image(PgdAnnotsDemo *demo) +{ + GtkFileChooser *chooser_dialog; + gint response; + const gchar *chooser_dir = "/usr/share/pixmaps"; + const gchar *pics_dir; + GtkFileFilter *filter; + + chooser_dialog = GTK_FILE_CHOOSER(gtk_file_chooser_dialog_new("Select PNG Image", NULL, GTK_FILE_CHOOSER_ACTION_OPEN, "gtk-cancel", GTK_RESPONSE_CANCEL, "gtk-open", GTK_RESPONSE_ACCEPT, NULL)); + gtk_window_set_modal(GTK_WINDOW(chooser_dialog), TRUE); + gtk_dialog_set_default_response(GTK_DIALOG(chooser_dialog), GTK_RESPONSE_ACCEPT); + + gtk_file_chooser_add_shortcut_folder(chooser_dialog, chooser_dir, NULL); + pics_dir = g_get_user_special_dir(G_USER_DIRECTORY_PICTURES); + if (pics_dir != NULL) { + gtk_file_chooser_add_shortcut_folder(chooser_dialog, pics_dir, NULL); + } + + if (!g_file_test(chooser_dir, G_FILE_TEST_IS_DIR)) { + chooser_dir = g_get_home_dir(); + } + + gtk_file_chooser_set_current_folder(chooser_dialog, chooser_dir); + + filter = gtk_file_filter_new(); + gtk_file_filter_set_name(filter, "PNG images"); + gtk_file_filter_add_mime_type(filter, "image/png"); + gtk_file_chooser_add_filter(chooser_dialog, filter); + filter = gtk_file_filter_new(); + gtk_file_filter_set_name(filter, "All Files"); + gtk_file_filter_add_pattern(filter, "*"); + gtk_file_chooser_add_filter(chooser_dialog, filter); + + response = gtk_dialog_run(GTK_DIALOG(chooser_dialog)); + + if (response == GTK_RESPONSE_ACCEPT) { + if (demo->custom_image_filename) { + g_free(demo->custom_image_filename); + } + + demo->custom_image_filename = gtk_file_chooser_get_filename(chooser_dialog); + } else { + if (demo->custom_image_filename) { + g_free(demo->custom_image_filename); + demo->custom_image_filename = NULL; + } + } + + gtk_widget_destroy(GTK_WIDGET(chooser_dialog)); +} + +static void stamp_selector_changed(GtkComboBox *combo_box, PgdAnnotsDemo *demo) +{ + GtkTreeModel *model; + GtkTreeIter iter; + gchar *active; + + model = gtk_combo_box_get_model(combo_box); + gtk_combo_box_get_active_iter(combo_box, &iter); + gtk_tree_model_get(model, &iter, 0, &active, -1); + if (strcmp(active, STAMP_CUSTOM_IMAGE) == 0) { + choose_custom_image(demo); + } +} + +static void type_selector_changed(GtkComboBox *combo_box, PgdAnnotsDemo *demo) +{ + GtkTreeModel *model; + GtkTreeIter iter; + int active; + + model = gtk_combo_box_get_model(combo_box); + gtk_combo_box_get_active_iter(combo_box, &iter); + gtk_tree_model_get(model, &iter, SELECTED_TYPE_COLUMN, &active, -1); + gtk_widget_set_sensitive(demo->stamp_selector, active == POPPLER_ANNOT_STAMP); +} + static gboolean pgd_annots_drawing_area_motion_notify(GtkWidget *area, GdkEventMotion *event, PgdAnnotsDemo *demo) { PopplerRectangle rect; @@ -1114,7 +1257,7 @@ GtkWidget *pgd_annots_create_widget(PopplerDocument *document) GtkWidget *label; GtkWidget *vbox, *vbox2; GtkWidget *button; - GtkWidget *hbox, *page_selector; + GtkWidget *hbox, *hbox2, *page_selector; GtkWidget *hpaned; GtkWidget *swindow, *treeview; GtkTreeSelection *selection; @@ -1138,6 +1281,7 @@ GtkWidget *pgd_annots_create_widget(PopplerDocument *document) vbox2 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6); hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6); + hbox2 = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 12); label = gtk_label_new("Page:"); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 0); @@ -1161,6 +1305,7 @@ GtkWidget *pgd_annots_create_widget(PopplerDocument *document) gtk_widget_show(demo->remove_button); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox2, FALSE, TRUE, 0); button = gtk_button_new_with_mnemonic("_Add"); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(pgd_annots_start_add_annot), (gpointer)demo); @@ -1175,8 +1320,25 @@ GtkWidget *pgd_annots_create_widget(PopplerDocument *document) } demo->type_selector = gtk_combo_box_new_with_model(GTK_TREE_MODEL(model)); + g_signal_connect(demo->type_selector, "changed", G_CALLBACK(type_selector_changed), (gpointer)demo); g_object_unref(model); + demo->stamp_selector = gtk_combo_box_text_new(); + for (i = 1; i < G_N_ELEMENTS(stamp_types) - 1; i++) { + gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(demo->stamp_selector), stamp_types[i]); + } + gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(demo->stamp_selector), STAMP_CUSTOM_IMAGE); + + gtk_combo_box_set_active(GTK_COMBO_BOX(demo->stamp_selector), 0); + g_signal_connect(demo->stamp_selector, "changed", G_CALLBACK(stamp_selector_changed), (gpointer)demo); + gtk_widget_set_sensitive(demo->stamp_selector, FALSE); + label = gtk_label_new("Stamp type: "); + gtk_widget_set_sensitive(label, FALSE); + g_object_bind_property(demo->stamp_selector, "sensitive", label, "sensitive", 0); + gtk_box_pack_end(GTK_BOX(hbox2), demo->stamp_selector, FALSE, FALSE, 0); + gtk_box_pack_end(GTK_BOX(hbox2), label, FALSE, TRUE, 0); + gtk_widget_show_all(hbox2); + renderer = gtk_cell_renderer_text_new(); gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(demo->type_selector), renderer, TRUE); gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(demo->type_selector), renderer, "text", SELECTED_LABEL_COLUMN, NULL); @@ -1193,6 +1355,7 @@ GtkWidget *pgd_annots_create_widget(PopplerDocument *document) gtk_widget_show(button); gtk_widget_show(hbox); + gtk_widget_show(hbox2); demo->timer_label = gtk_label_new(NULL); gtk_label_set_markup(GTK_LABEL(demo->timer_label), "<i>No annotations found</i>"); diff --git a/glib/poppler-annot.cc b/glib/poppler-annot.cc index 2c9a7607..b995f037 100644 --- a/glib/poppler-annot.cc +++ b/glib/poppler-annot.cc @@ -26,6 +26,7 @@ #define ZERO_CROPBOX(c) (!(c && (c->x1 > 0.01 || c->y1 > 0.01))) const PDFRectangle *_poppler_annot_get_cropbox_and_page(PopplerAnnot *poppler_annot, Page **page_out); +AnnotStampImageHelper *_poppler_convert_cairo_image_to_stamp_image_helper(cairo_surface_t *image, PDFDoc *doc, GError **error); /** * SECTION:poppler-annot @@ -44,6 +45,7 @@ typedef struct _PopplerAnnotScreenClass PopplerAnnotScreenClass; typedef struct _PopplerAnnotLineClass PopplerAnnotLineClass; typedef struct _PopplerAnnotCircleClass PopplerAnnotCircleClass; typedef struct _PopplerAnnotSquareClass PopplerAnnotSquareClass; +typedef struct _PopplerAnnotStampClass PopplerAnnotStampClass; struct _PopplerAnnotClass { @@ -153,6 +155,14 @@ struct _PopplerAnnotSquareClass { PopplerAnnotMarkupClass parent_class; }; +struct _PopplerAnnotStamp +{ + PopplerAnnot parent_instance; +}; +struct _PopplerAnnotStampClass +{ + PopplerAnnotClass parent_class; +}; G_DEFINE_TYPE(PopplerAnnot, poppler_annot, G_TYPE_OBJECT) G_DEFINE_TYPE(PopplerAnnotMarkup, poppler_annot_markup, POPPLER_TYPE_ANNOT) @@ -165,6 +175,7 @@ G_DEFINE_TYPE(PopplerAnnotScreen, poppler_annot_screen, POPPLER_TYPE_ANNOT) G_DEFINE_TYPE(PopplerAnnotLine, poppler_annot_line, POPPLER_TYPE_ANNOT_MARKUP) G_DEFINE_TYPE(PopplerAnnotCircle, poppler_annot_circle, POPPLER_TYPE_ANNOT_MARKUP) G_DEFINE_TYPE(PopplerAnnotSquare, poppler_annot_square, POPPLER_TYPE_ANNOT_MARKUP) +G_DEFINE_TYPE(PopplerAnnotStamp, poppler_annot_stamp, POPPLER_TYPE_ANNOT) static PopplerAnnot *_poppler_create_annot(GType annot_type, Annot *annot) { @@ -598,6 +609,141 @@ PopplerAnnot *poppler_annot_square_new(PopplerDocument *doc, PopplerRectangle *r return _poppler_annot_square_new(annot); } +static void poppler_annot_stamp_finalize(GObject *object) +{ + G_OBJECT_CLASS(poppler_annot_stamp_parent_class)->finalize(object); +} + +static void poppler_annot_stamp_init(PopplerAnnotStamp *poppler_annot) { } + +static void poppler_annot_stamp_class_init(PopplerAnnotStampClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS(klass); + + gobject_class->finalize = poppler_annot_stamp_finalize; +} + +PopplerAnnot *_poppler_annot_stamp_new(Annot *annot) +{ + PopplerAnnot *poppler_annot; + + poppler_annot = _poppler_create_annot(POPPLER_TYPE_ANNOT_STAMP, annot); + + return poppler_annot; +} + +/** + * poppler_annot_stamp_new: + * @doc: a #PopplerDocument + * @rect: a #PopplerRectangle + * + * Creates a new Stamp annotation that will be + * located on @rect when added to a page. See + * poppler_page_add_annot() + * + * Return value: a newly created #PopplerAnnotStamp annotation + * + * Since: 22.07.0 + **/ +PopplerAnnot *poppler_annot_stamp_new(PopplerDocument *doc, PopplerRectangle *rect) +{ + Annot *annot; + PDFRectangle pdf_rect(rect->x1, rect->y1, rect->x2, rect->y2); + + annot = new AnnotStamp(doc->doc, &pdf_rect); + + return _poppler_annot_stamp_new(annot); +} + +static gboolean get_raw_data_from_cairo_image(cairo_surface_t *image, cairo_format_t format, const int width, const int height, const size_t rowstride_c, GByteArray *data, GByteArray *soft_mask_data) +{ + gboolean has_alpha = format == CAIRO_FORMAT_ARGB32; + +#if G_BYTE_ORDER == G_LITTLE_ENDIAN + static const size_t CAIRO_B = 0; + static const size_t CAIRO_G = 1; + static const size_t CAIRO_R = 2; + static const size_t CAIRO_A = 3; +#elif G_BYTE_ORDER == G_BIG_ENDIAN + static const size_t CAIRO_A = 0; + static const size_t CAIRO_R = 1; + static const size_t CAIRO_G = 2; + static const size_t CAIRO_B = 3; +#else +# error "Unsupported endian type" +#endif + + cairo_surface_flush(image); + unsigned char *pixels_c = cairo_image_surface_get_data(image); + + if (format == CAIRO_FORMAT_ARGB32 || format == CAIRO_FORMAT_RGB24) { + unsigned char pixel[3]; + + for (int h = 0; h < height; h++) { + unsigned char *iter_c = pixels_c + h * rowstride_c; + for (int w = 0; w < width; w++) { + pixel[0] = iter_c[CAIRO_R]; + pixel[1] = iter_c[CAIRO_G]; + pixel[2] = iter_c[CAIRO_B]; + iter_c += 4; + + g_byte_array_append(data, (guint8 *)pixel, 3); + if (has_alpha) { + g_byte_array_append(soft_mask_data, (guint8 *)&iter_c[CAIRO_A], 1); + } + } + } + return TRUE; + } + + return FALSE; +} + +AnnotStampImageHelper *_poppler_convert_cairo_image_to_stamp_image_helper(cairo_surface_t *image, PDFDoc *doc, GError **error) +{ + AnnotStampImageHelper *annotImg; + GByteArray *data; + GByteArray *sMaskData; + + int bitsPerComponent; + const int width = cairo_image_surface_get_width(image); + const int height = cairo_image_surface_get_height(image); + const size_t rowstride_c = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width); + cairo_format_t format = cairo_image_surface_get_format(image); + + ColorSpace colorSpace; + + if (format == CAIRO_FORMAT_ARGB32 || format == CAIRO_FORMAT_RGB24) { + colorSpace = ColorSpace::DeviceRGB; + bitsPerComponent = 8; + } else { + g_set_error(error, POPPLER_ERROR, POPPLER_ERROR_INVALID, "Invalid or unsupported cairo image type %u", (unsigned int)format); + return nullptr; + } + + data = g_byte_array_sized_new((guint)((width * 4) + rowstride_c) * height); + sMaskData = g_byte_array_sized_new((guint)((width * 4) + rowstride_c) * height); + + if (!get_raw_data_from_cairo_image(image, format, width, height, rowstride_c, data, sMaskData)) { + g_set_error(error, POPPLER_ERROR, POPPLER_ERROR_INVALID, "Failed to get raw data from cairo image"); + g_byte_array_unref(data); + g_byte_array_unref(sMaskData); + return nullptr; + } + + if (sMaskData->len > 0) { + AnnotStampImageHelper sMask(doc, width, height, ColorSpace::DeviceGray, 8, (char *)sMaskData->data, (int)sMaskData->len); + annotImg = new AnnotStampImageHelper(doc, width, height, colorSpace, bitsPerComponent, (char *)data->data, (int)data->len, sMask.getRef()); + } else { + annotImg = new AnnotStampImageHelper(doc, width, height, colorSpace, bitsPerComponent, (char *)data->data, (int)data->len); + } + + g_byte_array_unref(data); + g_byte_array_unref(sMaskData); + + return annotImg; +} + /* Public methods */ /** * poppler_annot_get_annot_type: @@ -1911,3 +2057,145 @@ void poppler_annot_square_set_interior_color(PopplerAnnotSquare *poppler_annot, poppler_annot_geometry_set_interior_color(POPPLER_ANNOT(poppler_annot), poppler_color); } + +/** + * poppler_annot_stamp_get_icon: + * @poppler_annot: a #PopplerAnnotStamp + * + * Return value: the corresponding #PopplerAnnotStampIcon of the icon + * + * Since: 22.07.0 + */ +PopplerAnnotStampIcon poppler_annot_stamp_get_icon(PopplerAnnotStamp *poppler_annot) +{ + AnnotStamp *annot; + const GooString *text; + + g_return_val_if_fail(POPPLER_IS_ANNOT_STAMP(poppler_annot), POPPLER_ANNOT_STAMP_ICON_UNKNOWN); + + annot = static_cast<AnnotStamp *>(POPPLER_ANNOT(poppler_annot)->annot); + + text = annot->getIcon(); + + if (!text) { + return POPPLER_ANNOT_STAMP_ICON_NONE; + } + + if (!text->cmp("Approved")) { + return POPPLER_ANNOT_STAMP_ICON_APPROVED; + } else if (!text->cmp("AsIs")) { + return POPPLER_ANNOT_STAMP_ICON_AS_IS; + } else if (!text->cmp("Confidential")) { + return POPPLER_ANNOT_STAMP_ICON_CONFIDENTIAL; + } else if (!text->cmp("Final")) { + return POPPLER_ANNOT_STAMP_ICON_FINAL; + } else if (!text->cmp("Experimental")) { + return POPPLER_ANNOT_STAMP_ICON_EXPERIMENTAL; + } else if (!text->cmp("Expired")) { + return POPPLER_ANNOT_STAMP_ICON_EXPIRED; + } else if (!text->cmp("NotApproved")) { + return POPPLER_ANNOT_STAMP_ICON_NOT_APPROVED; + } else if (!text->cmp("NotForPublicRelease")) { + return POPPLER_ANNOT_STAMP_ICON_NOT_FOR_PUBLIC_RELEASE; + } else if (!text->cmp("Sold")) { + return POPPLER_ANNOT_STAMP_ICON_SOLD; + } else if (!text->cmp("Departmental")) { + return POPPLER_ANNOT_STAMP_ICON_DEPARTMENTAL; + } else if (!text->cmp("ForComment")) { + return POPPLER_ANNOT_STAMP_ICON_FOR_COMMENT; + } else if (!text->cmp("ForPublicRelease")) { + return POPPLER_ANNOT_STAMP_ICON_FOR_PUBLIC_RELEASE; + } else if (!text->cmp("TopSecret")) { + return POPPLER_ANNOT_STAMP_ICON_TOP_SECRET; + } + + return POPPLER_ANNOT_STAMP_ICON_UNKNOWN; +} + +/** + * poppler_annot_stamp_set_icon: + * @poppler_annot: a #PopplerAnnotStamp + * @icon: the #PopplerAnnotStampIcon type of the icon + * + * Sets the icon of @poppler_annot to be one of the predefined values in #PopplerAnnotStampIcon + * + * Since: 22.07.0 + */ +void poppler_annot_stamp_set_icon(PopplerAnnotStamp *poppler_annot, PopplerAnnotStampIcon icon) +{ + AnnotStamp *annot; + GooString *goo_str; + const gchar *text; + + g_return_if_fail(POPPLER_IS_ANNOT_STAMP(poppler_annot)); + + annot = static_cast<AnnotStamp *>(POPPLER_ANNOT(poppler_annot)->annot); + + if (icon == POPPLER_ANNOT_STAMP_ICON_NONE) { + annot->setIcon(nullptr); + return; + } + + if (icon == POPPLER_ANNOT_STAMP_ICON_APPROVED) { + text = "Approved"; + } else if (icon == POPPLER_ANNOT_STAMP_ICON_AS_IS) { + text = "AsIs"; + } else if (icon == POPPLER_ANNOT_STAMP_ICON_CONFIDENTIAL) { + text = "Confidential"; + } else if (icon == POPPLER_ANNOT_STAMP_ICON_FINAL) { + text = "Final"; + } else if (icon == POPPLER_ANNOT_STAMP_ICON_EXPERIMENTAL) { + text = "Experimental"; + } else if (icon == POPPLER_ANNOT_STAMP_ICON_EXPIRED) { + text = "Expired"; + } else if (icon == POPPLER_ANNOT_STAMP_ICON_NOT_APPROVED) { + text = "NotApproved"; + } else if (icon == POPPLER_ANNOT_STAMP_ICON_NOT_FOR_PUBLIC_RELEASE) { + text = "NotForPublicRelease"; + } else if (icon == POPPLER_ANNOT_STAMP_ICON_SOLD) { + text = "Sold"; + } else if (icon == POPPLER_ANNOT_STAMP_ICON_DEPARTMENTAL) { + text = "Departmental"; + } else if (icon == POPPLER_ANNOT_STAMP_ICON_FOR_COMMENT) { + text = "ForComment"; + } else if (icon == POPPLER_ANNOT_STAMP_ICON_FOR_PUBLIC_RELEASE) { + text = "ForPublicRelease"; + } else if (icon == POPPLER_ANNOT_STAMP_ICON_TOP_SECRET) { + text = "TopSecret"; + } else { + return; /* POPPLER_ANNOT_STAMP_ICON_UNKNOWN */ + } + + goo_str = new GooString(text); + annot->setIcon(goo_str); + delete goo_str; +} + +/** + * poppler_annot_stamp_set_custom_image: + * @poppler_annot: a #PopplerAnnotStamp + * @image: an image cairo surface + * @error: (nullable): return location for error, or %NULL. + * + * Sets the custom image of @poppler_annot to be @image + * + * Return value: %TRUE on success, %FALSE otherwise. + * + * Since: 22.07.0 + */ +gboolean poppler_annot_stamp_set_custom_image(PopplerAnnotStamp *poppler_annot, cairo_surface_t *image, GError **error) +{ + AnnotStamp *annot; + AnnotStampImageHelper *annot_image_helper; + + g_return_val_if_fail(POPPLER_IS_ANNOT_STAMP(poppler_annot), FALSE); + + annot = static_cast<AnnotStamp *>(POPPLER_ANNOT(poppler_annot)->annot); + annot_image_helper = _poppler_convert_cairo_image_to_stamp_image_helper(image, annot->getDoc(), error); + if (!annot_image_helper) { + return FALSE; + } + annot->setCustomImage(annot_image_helper); + + return TRUE; +} diff --git a/glib/poppler-annot.h b/glib/poppler-annot.h index da55172d..509ecdff 100644 --- a/glib/poppler-annot.h +++ b/glib/poppler-annot.h @@ -72,6 +72,10 @@ G_BEGIN_DECLS #define POPPLER_ANNOT_SQUARE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), POPPLER_TYPE_ANNOT_SQUARE, PopplerAnnotSquare)) #define POPPLER_IS_ANNOT_SQUARE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), POPPLER_TYPE_ANNOT_SQUARE)) +#define POPPLER_TYPE_ANNOT_STAMP (poppler_annot_stamp_get_type()) +#define POPPLER_ANNOT_STAMP(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), POPPLER_TYPE_ANNOT_STAMP, PopplerAnnotStamp)) +#define POPPLER_IS_ANNOT_STAMP(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), POPPLER_TYPE_ANNOT_STAMP)) + typedef enum { POPPLER_ANNOT_UNKNOWN, @@ -169,6 +173,25 @@ struct _PopplerAnnotCalloutLine gdouble y3; }; +typedef enum +{ + POPPLER_ANNOT_STAMP_ICON_UNKNOWN = 0, + POPPLER_ANNOT_STAMP_ICON_APPROVED, + POPPLER_ANNOT_STAMP_ICON_AS_IS, + POPPLER_ANNOT_STAMP_ICON_CONFIDENTIAL, + POPPLER_ANNOT_STAMP_ICON_FINAL, + POPPLER_ANNOT_STAMP_ICON_EXPERIMENTAL, + POPPLER_ANNOT_STAMP_ICON_EXPIRED, + POPPLER_ANNOT_STAMP_ICON_NOT_APPROVED, + POPPLER_ANNOT_STAMP_ICON_NOT_FOR_PUBLIC_RELEASE, + POPPLER_ANNOT_STAMP_ICON_SOLD, + POPPLER_ANNOT_STAMP_ICON_DEPARTMENTAL, + POPPLER_ANNOT_STAMP_ICON_FOR_COMMENT, + POPPLER_ANNOT_STAMP_ICON_FOR_PUBLIC_RELEASE, + POPPLER_ANNOT_STAMP_ICON_TOP_SECRET, + POPPLER_ANNOT_STAMP_ICON_NONE +} PopplerAnnotStampIcon; + POPPLER_PUBLIC GType poppler_annot_get_type(void) G_GNUC_CONST; POPPLER_PUBLIC @@ -328,6 +351,18 @@ void poppler_annot_square_set_interior_color(PopplerAnnotSquare *poppler_annot, POPPLER_PUBLIC PopplerColor *poppler_annot_square_get_interior_color(PopplerAnnotSquare *poppler_annot); +/* PopplerAnnotStamp */ +POPPLER_PUBLIC +GType poppler_annot_stamp_get_type(void) G_GNUC_CONST; +POPPLER_PUBLIC +PopplerAnnot *poppler_annot_stamp_new(PopplerDocument *doc, PopplerRectangle *rect); +POPPLER_PUBLIC +PopplerAnnotStampIcon poppler_annot_stamp_get_icon(PopplerAnnotStamp *poppler_annot); +POPPLER_PUBLIC +void poppler_annot_stamp_set_icon(PopplerAnnotStamp *poppler_annot, PopplerAnnotStampIcon icon); +POPPLER_PUBLIC +gboolean poppler_annot_stamp_set_custom_image(PopplerAnnotStamp *poppler_annot, cairo_surface_t *image, GError **error); + G_END_DECLS #endif /* __POPPLER_ANNOT_H__ */ diff --git a/glib/poppler-page.cc b/glib/poppler-page.cc index 8e361a58..7f47cd5b 100644 --- a/glib/poppler-page.cc +++ b/glib/poppler-page.cc @@ -1337,6 +1337,9 @@ GList *poppler_page_get_annot_mapping(PopplerPage *page) case Annot::typeStrikeOut: mapping->annot = _poppler_annot_text_markup_new(annot); break; + case Annot::typeStamp: + mapping->annot = _poppler_annot_stamp_new(annot); + break; default: mapping->annot = _poppler_annot_new(annot); break; diff --git a/glib/poppler-private.h b/glib/poppler-private.h index ce2c4733..758c7021 100644 --- a/glib/poppler-private.h +++ b/glib/poppler-private.h @@ -156,6 +156,7 @@ PopplerAnnot *_poppler_annot_screen_new(PopplerDocument *doc, Annot *annot); PopplerAnnot *_poppler_annot_line_new(Annot *annot); PopplerAnnot *_poppler_annot_circle_new(Annot *annot); PopplerAnnot *_poppler_annot_square_new(Annot *annot); +PopplerAnnot *_poppler_annot_stamp_new(Annot *annot); const PDFRectangle *_poppler_annot_get_cropbox(PopplerAnnot *poppler_annot); @@ -163,6 +164,7 @@ char *_poppler_goo_string_to_utf8(const GooString *s); gboolean _poppler_convert_pdf_date_to_gtime(const GooString *date, time_t *gdate); GDateTime *_poppler_convert_pdf_date_to_date_time(const GooString *date); GooString *_poppler_convert_date_time_to_pdf_date(GDateTime *datetime); +AnnotStampImageHelper *_poppler_convert_cairo_image_to_stamp_image_helper(const cairo_surface_t *image); void _poppler_error_cb(ErrorCategory category, Goffset pos, const char *message); diff --git a/glib/poppler.h b/glib/poppler.h index e2001504..710b7b23 100644 --- a/glib/poppler.h +++ b/glib/poppler.h @@ -219,6 +219,7 @@ typedef struct _PopplerStructureElementIter PopplerStructureElementIter; typedef struct _PopplerTextSpan PopplerTextSpan; typedef struct _PopplerPageRange PopplerPageRange; typedef struct _PopplerSignatureInfo PopplerSignatureInfo; +typedef struct _PopplerAnnotStamp PopplerAnnotStamp; /** * PopplerBackend: diff --git a/glib/reference/poppler-sections.txt b/glib/reference/poppler-sections.txt index 0a20ffae..f027cd03 100644 --- a/glib/reference/poppler-sections.txt +++ b/glib/reference/poppler-sections.txt @@ -455,6 +455,7 @@ PopplerAnnotMarkup PopplerAnnotMovie PopplerAnnotScreen PopplerAnnotSquare +PopplerAnnotStamp PopplerAnnotText PopplerAnnotTextMarkup PopplerAnnotExternalDataType @@ -462,6 +463,7 @@ PopplerAnnotFlag PopplerAnnotFreeTextQuadding PopplerAnnotMarkupReplyType PopplerAnnotTextState +PopplerAnnotStampIcon PopplerAnnotType poppler_annot_get_annot_type POPPLER_ANNOT_TEXT_ICON_CIRCLE @@ -516,6 +518,10 @@ poppler_annot_set_rectangle poppler_annot_square_get_interior_color poppler_annot_square_new poppler_annot_square_set_interior_color +poppler_annot_stamp_get_icon +poppler_annot_stamp_new +poppler_annot_stamp_set_custom_image +poppler_annot_stamp_set_icon poppler_annot_text_get_icon poppler_annot_text_get_is_open poppler_annot_text_get_state @@ -539,6 +545,7 @@ POPPLER_ANNOT_MARKUP POPPLER_ANNOT_MOVIE POPPLER_ANNOT_SCREEN POPPLER_ANNOT_SQUARE +POPPLER_ANNOT_STAMP POPPLER_ANNOT_TEXT POPPLER_ANNOT_TEXT_MARKUP POPPLER_IS_ANNOT @@ -550,6 +557,7 @@ POPPLER_IS_ANNOT_MARKUP POPPLER_IS_ANNOT_MOVIE POPPLER_IS_ANNOT_SCREEN POPPLER_IS_ANNOT_SQUARE +POPPLER_IS_ANNOT_STAMP POPPLER_IS_ANNOT_TEXT POPPLER_IS_ANNOT_TEXT_MARKUP POPPLER_TYPE_ANNOT @@ -566,6 +574,7 @@ POPPLER_TYPE_ANNOT_MARKUP_REPLY_TYPE POPPLER_TYPE_ANNOT_MOVIE POPPLER_TYPE_ANNOT_SCREEN POPPLER_TYPE_ANNOT_SQUARE +POPPLER_TYPE_ANNOT_STAMP POPPLER_TYPE_ANNOT_TEXT POPPLER_TYPE_ANNOT_TEXT_MARKUP POPPLER_TYPE_ANNOT_TEXT_STATE @@ -584,6 +593,7 @@ poppler_annot_markup_reply_type_get_type poppler_annot_movie_get_type poppler_annot_screen_get_type poppler_annot_square_get_type +poppler_annot_stamp_get_type poppler_annot_text_get_type poppler_annot_text_markup_get_type poppler_annot_text_state_get_type diff --git a/glib/reference/poppler.types b/glib/reference/poppler.types index da524e0e..1ab636b3 100644 --- a/glib/reference/poppler.types +++ b/glib/reference/poppler.types @@ -18,6 +18,7 @@ poppler_annot_markup_reply_type_get_type poppler_annot_movie_get_type poppler_annot_screen_get_type poppler_annot_square_get_type +poppler_annot_stamp_get_type poppler_annot_text_get_type poppler_annot_text_markup_get_type poppler_annot_text_state_get_type