| //======================================================================== |
| // |
| // pdf-inspector.cc |
| // |
| // Copyright 2005 Jonathan Blandford <jrb@redhat.com> |
| // Copyright 2018 Adam Reichold <adam.reichold@t-online.de> |
| // |
| //======================================================================== |
| |
| #include <config.h> |
| |
| #include <goo/gmem.h> |
| #include <goo/GooTimer.h> |
| #include <splash/SplashTypes.h> |
| #include <splash/SplashBitmap.h> |
| #include "Object.h" |
| #include "ProfileData.h" |
| #include "GfxState.h" |
| |
| #include <gdk/gdk.h> |
| #include "CairoOutputDev.h" |
| |
| #include "PDFDoc.h" |
| #include "GlobalParams.h" |
| #include "ErrorCodes.h" |
| #include <gtk/gtk.h> |
| |
| |
| // Mapping |
| #include "pdf-operators.c" |
| |
| enum { |
| OP_STRING, |
| OP_COUNT, |
| OP_TOTAL, |
| OP_MIN, |
| OP_MAX, |
| N_COLUMNS |
| }; |
| |
| class PdfInspector { |
| public: |
| |
| PdfInspector(void); |
| |
| void set_file_name (const char *file_name); |
| void load (const char *file_name); |
| void run (void); |
| void error_dialog (const char *error_message); |
| void analyze_page (int page); |
| |
| private: |
| static void on_file_activated (GtkWidget *widget, PdfInspector *inspector); |
| static void on_selection_changed (GtkTreeSelection *selection, PdfInspector *inspector); |
| static void on_analyze_clicked (GtkWidget *widget, PdfInspector *inspector); |
| |
| GtkBuilder* builder; |
| GtkTreeModel *model; |
| PDFDoc *doc; |
| CairoOutputDev *output; |
| }; |
| |
| |
| |
| PdfInspector::PdfInspector(void) |
| { |
| GtkWidget *widget; |
| GError* error = nullptr; |
| |
| builder = gtk_builder_new (); |
| |
| if (!gtk_builder_add_from_file (builder, "./pdf-inspector.ui", &error)) |
| { |
| g_warning ("Couldn't load builder file: %s", error->message); |
| g_error_free (error); |
| } |
| |
| widget = GTK_WIDGET (gtk_builder_get_object (builder, "pdf_file_chooser_button")); |
| g_signal_connect (widget, "selection-changed", G_CALLBACK (on_file_activated), this); |
| |
| widget = GTK_WIDGET (gtk_builder_get_object (builder, "analyze_button")); |
| g_signal_connect (widget, "clicked", G_CALLBACK (on_analyze_clicked), this); |
| |
| // setup the TreeView |
| widget = GTK_WIDGET (gtk_builder_get_object (builder, "pdf_tree_view")); |
| g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (widget)), |
| "changed", G_CALLBACK (on_selection_changed), this); |
| model = (GtkTreeModel *)gtk_list_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_INT, |
| G_TYPE_DOUBLE, G_TYPE_DOUBLE, G_TYPE_DOUBLE); |
| gtk_tree_view_set_model (GTK_TREE_VIEW (widget), model); |
| gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (widget), |
| 0, "Operation", |
| gtk_cell_renderer_text_new (), |
| "text", OP_STRING, |
| NULL); |
| |
| gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (widget), |
| 1, "Count", |
| gtk_cell_renderer_text_new (), |
| "text", OP_COUNT, |
| NULL); |
| |
| gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (widget), |
| 2, "Elapsed", |
| gtk_cell_renderer_text_new (), |
| "text", OP_TOTAL, |
| NULL); |
| |
| gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (widget), |
| 3, "Min", |
| gtk_cell_renderer_text_new (), |
| "text", OP_MIN, |
| NULL); |
| |
| gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (widget), |
| 4, "Max", |
| gtk_cell_renderer_text_new (), |
| "text", OP_MAX, |
| NULL); |
| |
| for (int i = 0; i < N_COLUMNS; i++) |
| { |
| GtkTreeViewColumn *column; |
| |
| column = gtk_tree_view_get_column (GTK_TREE_VIEW (widget), i); |
| gtk_tree_view_column_set_sort_column_id (column, i); |
| } |
| doc = nullptr; |
| output = new CairoOutputDev(); |
| output->setPrinting (false); |
| |
| // set up initial widgets |
| load (nullptr); |
| } |
| |
| void |
| PdfInspector::set_file_name(const char *file_name) |
| { |
| GtkWidget *widget; |
| |
| widget = GTK_WIDGET (gtk_builder_get_object (builder, "pdf_file_chooser_button")); |
| gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (widget), file_name); |
| } |
| |
| void |
| PdfInspector::on_file_activated (GtkWidget *widget, PdfInspector *inspector) |
| { |
| gchar *file_name; |
| |
| file_name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget)); |
| if (file_name) |
| inspector->load (file_name); |
| |
| g_free (file_name); |
| } |
| |
| void |
| PdfInspector::on_selection_changed (GtkTreeSelection *selection, PdfInspector *inspector) |
| { |
| GtkWidget *label; |
| size_t i; |
| GtkTreeModel *model; |
| GtkTreeIter iter; |
| gchar *op = nullptr; |
| |
| label = GTK_WIDGET (gtk_builder_get_object (inspector->builder, "description_label")); |
| gtk_label_set_markup (GTK_LABEL (label), "<i>No Description</i>"); |
| |
| if (gtk_tree_selection_get_selected (selection, &model, &iter)) |
| { |
| gtk_tree_model_get (model, &iter, |
| OP_STRING, &op, |
| -1); |
| |
| } |
| |
| if (op == nullptr) |
| return; |
| |
| for (i = 0; i < G_N_ELEMENTS (op_mapping); i++) |
| { |
| |
| if (!strcmp (op, op_mapping[i].op)) |
| { |
| gchar *text; |
| text = g_strdup_printf ("<i>%s</i>", op_mapping[i].description); |
| gtk_label_set_markup (GTK_LABEL (label), text); |
| g_free (text); |
| break; |
| } |
| } |
| |
| g_free (op); |
| } |
| |
| void |
| PdfInspector::on_analyze_clicked (GtkWidget *widget, PdfInspector *inspector) |
| { |
| GtkWidget *spin; |
| int page; |
| |
| spin = GTK_WIDGET (gtk_builder_get_object (inspector->builder, "pdf_spin")); |
| |
| page = (int) gtk_spin_button_get_value (GTK_SPIN_BUTTON (spin)); |
| |
| inspector->analyze_page (page); |
| |
| } |
| |
| void |
| PdfInspector::analyze_page (int page) |
| { |
| GtkWidget *label; |
| char *text; |
| cairo_t *cr; |
| cairo_surface_t *surface; |
| |
| label = GTK_WIDGET (gtk_builder_get_object (builder, "pdf_total_label")); |
| |
| output->startProfile (); |
| gtk_list_store_clear (GTK_LIST_STORE (model)); |
| |
| GooTimer timer; |
| surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, |
| doc->getPageCropWidth(page + 1), |
| doc->getPageCropHeight(page + 1)); |
| cr = cairo_create (surface); |
| cairo_surface_destroy (surface); |
| output->setCairo (cr); |
| cairo_destroy (cr); |
| doc->displayPage (output, page + 1, 72, 72, 0, false, true, false); |
| output->setCairo (nullptr); |
| |
| // Total time; |
| text = g_strdup_printf ("%g", timer.getElapsed ()); |
| gtk_label_set_text (GTK_LABEL (label), text); |
| g_free (text); |
| |
| // Individual times; |
| auto hash = output->endProfile (); |
| for (const auto& kvp : *hash) |
| { |
| GtkTreeIter tree_iter; |
| const auto* const data_p = &kvp.second; |
| |
| gtk_list_store_append (GTK_LIST_STORE (model), &tree_iter); |
| gtk_list_store_set (GTK_LIST_STORE (model), &tree_iter, |
| OP_STRING, kvp.first.c_str (), |
| OP_COUNT, data_p->getCount (), |
| OP_TOTAL, data_p->getTotal (), |
| OP_MIN, data_p->getMin (), |
| OP_MAX, data_p->getMax (), |
| -1); |
| } |
| } |
| |
| void |
| PdfInspector::load(const char *file_name) |
| { |
| GtkWidget *spin; |
| GtkWidget *button; |
| GtkWidget *label; |
| |
| // kill the old PDF file |
| if (doc != nullptr) |
| { |
| delete doc; |
| doc = nullptr; |
| } |
| |
| // load the new file |
| if (file_name) |
| { |
| GooString *filename_g; |
| |
| filename_g = new GooString (file_name); |
| doc = new PDFDoc(filename_g, nullptr, nullptr); |
| } |
| |
| if (doc && !doc->isOk()) |
| { |
| this->error_dialog ("Failed to load file."); |
| delete doc; |
| doc = nullptr; |
| } |
| |
| spin = GTK_WIDGET (gtk_builder_get_object (builder, "pdf_spin")); |
| button = GTK_WIDGET (gtk_builder_get_object (builder, "analyze_button")); |
| label = GTK_WIDGET (gtk_builder_get_object (builder, "pdf_total_label")); |
| gtk_label_set_text (GTK_LABEL (label), ""); |
| |
| if (doc) |
| { |
| gtk_widget_set_sensitive (spin, TRUE); |
| gtk_widget_set_sensitive (button, TRUE); |
| gtk_widget_set_sensitive (label, TRUE); |
| gtk_spin_button_set_range (GTK_SPIN_BUTTON (spin), 0, doc->getNumPages()-1); |
| gtk_spin_button_set_value (GTK_SPIN_BUTTON (spin), 0); |
| |
| output->startDoc (doc); |
| } |
| else |
| { |
| gtk_widget_set_sensitive (spin, FALSE); |
| gtk_widget_set_sensitive (button, FALSE); |
| gtk_widget_set_sensitive (label, FALSE); |
| } |
| } |
| |
| void |
| PdfInspector::error_dialog (const char *error_message) |
| { |
| g_warning ("%s", error_message); |
| } |
| |
| void |
| PdfInspector::run() |
| { |
| GtkWidget *dialog; |
| |
| dialog = GTK_WIDGET (gtk_builder_get_object (builder, "pdf_dialog")); |
| |
| gtk_dialog_run (GTK_DIALOG (dialog)); |
| } |
| |
| |
| |
| int |
| main (int argc, char *argv []) |
| { |
| const char *file_name = nullptr; |
| PdfInspector *inspector; |
| |
| gtk_init (&argc, &argv); |
| |
| globalParams = new GlobalParams(); |
| globalParams->setProfileCommands (true); |
| globalParams->setPrintCommands (true); |
| |
| if (argc == 2) |
| file_name = argv[1]; |
| else if (argc > 2) |
| { |
| fprintf (stderr, "usage: %s [PDF-FILE]\n", argv[0]); |
| return -1; |
| } |
| |
| inspector = new PdfInspector (); |
| |
| if (file_name) |
| inspector->set_file_name (file_name); |
| |
| inspector->run (); |
| |
| delete inspector; |
| delete globalParams; |
| |
| return 0; |
| } |
| |
| |