Spaces:
Sleeping
Sleeping
//======================================================================== | |
// | |
// pdf-inspector.cc | |
// | |
// Copyright 2005 Jonathan Blandford <[email protected]> | |
// Copyright 2018 Adam Reichold <[email protected]> | |
// Copyright 2019, 2022 Albert Astals Cid <[email protected]> | |
// | |
//======================================================================== | |
// Mapping | |
enum | |
{ | |
OP_STRING, | |
OP_COUNT, | |
OP_TOTAL, | |
OP_MIN, | |
OP_MAX, | |
N_COLUMNS | |
}; | |
class PdfInspector | |
{ | |
public: | |
PdfInspector(); | |
void set_file_name(const char *file_name); | |
void load(const char *file_name); | |
void run(); | |
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() | |
{ | |
GtkWidget *widget; | |
GError *error = nullptr; | |
builder = gtk_builder_new(); | |
if (!gtk_builder_add_from_file(builder, SRC_DIR "/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) { | |
doc = new PDFDoc(std::make_unique<GooString>(file_name)); | |
} | |
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 = std::make_unique<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; | |
return 0; | |
} | |