//======================================================================== // // GDKSplashOutputDev.cc // // Copyright 2003 Glyph & Cog, LLC // Copyright 2004 Red Hat, Inc. (GDK port) // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include #include #include #include #include "Object.h" #include "ProfileData.h" #include "GfxState.h" #include #include "CairoOutputDev.h" #include "PDFDoc.h" #include "GlobalParams.h" #include "ErrorCodes.h" #include // 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 = NULL; 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 = NULL; output = new CairoOutputDev(); // set up initial widgets load (NULL); } 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 = NULL; label = GTK_WIDGET (gtk_builder_get_object (inspector->builder, "description_label")); gtk_label_set_markup (GTK_LABEL (label), "No Description"); if (gtk_tree_selection_get_selected (selection, &model, &iter)) { gtk_tree_model_get (model, &iter, OP_STRING, &op, -1); } if (op == NULL) return; for (i = 0; i < G_N_ELEMENTS (op_mapping); i++) { if (!strcmp (op, op_mapping[i].op)) { gchar *text; text = g_strdup_printf ("%s", 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) { GooHashIter *iter; GooHash *hash; GooString *key; void *p; 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, gFalse, gTrue, gTrue); output->setCairo (NULL); // Total time; text = g_strdup_printf ("%g", timer.getElapsed ()); gtk_label_set_text (GTK_LABEL (label), text); g_free (text); // Individual times; hash = output->endProfile (); hash->startIter(&iter); while (hash->getNext(&iter, &key, &p)) { GtkTreeIter tree_iter; ProfileData *data_p = (ProfileData *) p; gtk_list_store_append (GTK_LIST_STORE (model), &tree_iter); gtk_list_store_set (GTK_LIST_STORE (model), &tree_iter, OP_STRING, key->getCString(), OP_COUNT, data_p->getCount (), OP_TOTAL, data_p->getTotal (), OP_MIN, data_p->getMin (), OP_MAX, data_p->getMax (), -1); } hash->killIter(&iter); deleteGooHash (hash, ProfileData); } void PdfInspector::load(const char *file_name) { GtkWidget *spin; GtkWidget *button; GtkWidget *label; // kill the old PDF file if (doc != NULL) { delete doc; doc = NULL; } // load the new file if (file_name) { GooString *filename_g; filename_g = new GooString (file_name); doc = new PDFDoc(filename_g, 0, 0); delete filename_g; } if (doc && !doc->isOk()) { this->error_dialog ("Failed to load file."); delete doc; doc = NULL; } 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->getXRef(), doc->getCatalog()); } 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 = NULL; 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; }