Printing, Image and attachment export

Added following functionality:
  * Save images
  * Save attachments
  * Simple printing support

Fixes and other changes:
  * Additional rectangle calculation function
  * Search and link clicking fix

Other:
  * Added license file
This commit is contained in:
Moritz Lipp 2009-08-29 16:07:58 +02:00
parent 01e613adc0
commit 54149584f1
4 changed files with 204 additions and 57 deletions

21
LICENSE Normal file
View file

@ -0,0 +1,21 @@
Copyright (c) 2009 ML, JY
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.

9
README
View file

@ -1,12 +1,11 @@
zathura - pdf viewer zathura - pdf viewer
-------------------- --------------------
zathura is an pdf viewer based on the poppler pdf rendering library zathura is a pdf viewer based on the poppler pdf rendering library
Requirements Requirements
------------ ------------
poppler (0.10.7-2) poppler-glib (0.10.7)
poppler-glib (0.10.7-1) gtk2 (2.17.2)
gtk2 (2.16.5-1)
Configuration Configuration
------------- -------------
@ -30,5 +29,3 @@ Use zathura
Just run: Just run:
zathura <file> zathura <file>

View file

@ -6,7 +6,7 @@ static const int SHOW_NOTIFICATION = 5;
static const int DEFAULT_WIDTH = 800; static const int DEFAULT_WIDTH = 800;
static const int DEFAULT_HEIGHT = 600; static const int DEFAULT_HEIGHT = 600;
static const char BROWSER[] = "firefox %s"; static const char BROWSER[] = "firefox %s";
static const char PRINTER[] = "EPSON_AL-CX11_192.168.88.80";
/* look */ /* look */
static const char font[] = "monospace normal 9"; static const char font[] = "monospace normal 9";
static const char default_bgcolor[] = "#000000"; static const char default_bgcolor[] = "#000000";
@ -39,7 +39,7 @@ Shortcut shortcuts[] = {
{GDK_CONTROL_MASK, GDK_0, sc_zoom, { ZOOM_ORIGINAL } }, {GDK_CONTROL_MASK, GDK_0, sc_zoom, { ZOOM_ORIGINAL } },
{GDK_CONTROL_MASK, GDK_r, sc_rotate, { RIGHT } }, {GDK_CONTROL_MASK, GDK_r, sc_rotate, { RIGHT } },
{GDK_CONTROL_MASK, GDK_e, sc_rotate, { LEFT } }, {GDK_CONTROL_MASK, GDK_e, sc_rotate, { LEFT } },
{GDK_CONTROL_MASK, GDK_p, sc_print, {0} }, {GDK_CONTROL_MASK, GDK_p, sc_focus_inputbar, { .data = ":print all" } },
{GDK_CONTROL_MASK, GDK_q, sc_quit, {0} }, {GDK_CONTROL_MASK, GDK_q, sc_quit, {0} },
{0, GDK_n, sc_search, { FORWARD } }, {0, GDK_n, sc_search, { FORWARD } },
{0, GDK_N, sc_search, { BACKWARD } }, {0, GDK_N, sc_search, { BACKWARD } },
@ -67,6 +67,7 @@ Command commands[] = {
{"info", cmd_info}, {"info", cmd_info},
{"links", cmd_links}, {"links", cmd_links},
{"open", cmd_open}, {"open", cmd_open},
{"print", cmd_print},
{"rotate", cmd_rotate}, {"rotate", cmd_rotate},
{"quit", cmd_quit}, {"quit", cmd_quit},
{"zoom", cmd_zoom}, {"zoom", cmd_zoom},

226
zathura.c
View file

@ -13,8 +13,8 @@
/* enums */ /* enums */
enum { UP, DOWN, LEFT, RIGHT, ZOOM_IN, ZOOM_OUT, ZOOM_ORIGINAL, enum { UP, DOWN, LEFT, RIGHT, ZOOM_IN, ZOOM_OUT, ZOOM_ORIGINAL,
NEXT, PREVIOUS, HIDE, ERROR, WARNING, DEFAULT, TOP, BOTTOM, NEXT, PREVIOUS, HIDE, ERROR, WARNING, DEFAULT, TOP, BOTTOM,
ADJUST_BESTFIT, ADJUST_WIDTH, FORWARD, BACKWARD }; ADJUST_BESTFIT, ADJUST_WIDTH, FORWARD, BACKWARD };
struct struct
{ {
@ -87,6 +87,8 @@ void set_page(int);
void draw(); void draw();
void highlight_result(PopplerRectangle*); void highlight_result(PopplerRectangle*);
void open_link(char*); void open_link(char*);
void save_images(int, char*);
void save_attachments(char*);
gboolean complete(Argument*); gboolean complete(Argument*);
gboolean delete_widget(gpointer); gboolean delete_widget(gpointer);
@ -94,6 +96,8 @@ gboolean delete_widget(gpointer);
GtkWidget* notify(int, char*); GtkWidget* notify(int, char*);
GtkWidget* update_notification(GtkWidget*, int, char*); GtkWidget* update_notification(GtkWidget*, int, char*);
PopplerRectangle* recalcRectangle(PopplerRectangle*);
/* shortcut declarations */ /* shortcut declarations */
void sc_focus_inputbar(Argument*); void sc_focus_inputbar(Argument*);
void sc_scroll(Argument*); void sc_scroll(Argument*);
@ -102,7 +106,6 @@ void sc_zoom(Argument*);
void sc_adjust_window(Argument*); void sc_adjust_window(Argument*);
void sc_rotate(Argument*); void sc_rotate(Argument*);
void sc_search(Argument*); void sc_search(Argument*);
void sc_print(Argument*);
void sc_quit(Argument*); void sc_quit(Argument*);
/* command declarations */ /* command declarations */
@ -111,6 +114,7 @@ void cmd_goto(int, char**);
void cmd_info(int, char**); void cmd_info(int, char**);
void cmd_links(int, char**); void cmd_links(int, char**);
void cmd_open(int, char**); void cmd_open(int, char**);
void cmd_print(int, char**);
void cmd_rotate(int, char**); void cmd_rotate(int, char**);
void cmd_quit(int, char**); void cmd_quit(int, char**);
void cmd_zoom(int, char**); void cmd_zoom(int, char**);
@ -258,7 +262,6 @@ update_notification(GtkWidget* view, int level, char* text)
{ {
gtk_widget_modify_fg(GTK_WIDGET(message), GTK_STATE_NORMAL, &(Zathura.Settings.notification_fg)); gtk_widget_modify_fg(GTK_WIDGET(message), GTK_STATE_NORMAL, &(Zathura.Settings.notification_fg));
gtk_widget_modify_bg(GTK_WIDGET(view), GTK_STATE_NORMAL, &(Zathura.Settings.notification_bg)); gtk_widget_modify_bg(GTK_WIDGET(view), GTK_STATE_NORMAL, &(Zathura.Settings.notification_bg));
} }
if(gtk_bin_get_child(GTK_BIN(view))) if(gtk_bin_get_child(GTK_BIN(view)))
@ -269,6 +272,47 @@ update_notification(GtkWidget* view, int level, char* text)
return GTK_WIDGET(view); return GTK_WIDGET(view);
} }
PopplerRectangle*
recalcRectangle(PopplerRectangle* rectangle)
{
double page_width, page_height;
double x1 = rectangle->x1;
double x2 = rectangle->x2;
double y1 = rectangle->y1;
double y2 = rectangle->y2;
poppler_page_get_size(Zathura.PDF.page, &page_width, &page_height);
switch(Zathura.PDF.rotate)
{
case 90:
rectangle->x1 = (page_height - y2) * Zathura.PDF.scale;
rectangle->y1 = x1 * Zathura.PDF.scale;
rectangle->x2 = (page_height - y1) * Zathura.PDF.scale;
rectangle->y2 = x2 * Zathura.PDF.scale;
break;
case 180:
rectangle->x1 = (page_width - x2) * Zathura.PDF.scale;
rectangle->y1 = (page_height - y2) * Zathura.PDF.scale;
rectangle->x2 = (page_width - x1) * Zathura.PDF.scale;
rectangle->y2 = (page_height - y1) * Zathura.PDF.scale;
break;
case 270:
rectangle->x1 = y1 * Zathura.PDF.scale;
rectangle->y1 = (page_width - x2) * Zathura.PDF.scale;
rectangle->x2 = y2 * Zathura.PDF.scale;
rectangle->y2 = (page_width - x1) * Zathura.PDF.scale;
break;
default:
rectangle->x1 = x1 * Zathura.PDF.scale;
rectangle->y1 = y1 * Zathura.PDF.scale;
rectangle->x2 = x2 * Zathura.PDF.scale;
rectangle->y2 = y2 * Zathura.PDF.scale;
}
return rectangle;
}
void void
update_status() update_status()
{ {
@ -361,34 +405,13 @@ draw()
void void
highlight_result(PopplerRectangle* rectangle) highlight_result(PopplerRectangle* rectangle)
{ {
double page_height, page_width;
double width, height;
double scale;
poppler_page_get_size(Zathura.PDF.page, &page_width, &page_height);
scale = Zathura.PDF.scale;
width = (rectangle->x2 - rectangle->x1) * scale;
height = (rectangle->y2 - rectangle->y1) * scale;
cairo_t *cairo = cairo_create(Zathura.PDF.surface); cairo_t *cairo = cairo_create(Zathura.PDF.surface);
cairo_set_source_rgba(cairo, Zathura.Settings.search_highlight.red, Zathura.Settings.search_highlight.green, cairo_set_source_rgba(cairo, Zathura.Settings.search_highlight.red, Zathura.Settings.search_highlight.green,
Zathura.Settings.search_highlight.blue, HL_TRANSPARENCY); Zathura.Settings.search_highlight.blue, HL_TRANSPARENCY);
switch(Zathura.PDF.rotate) rectangle = recalcRectangle(rectangle);
{
case 90: cairo_rectangle(cairo, rectangle->x1, rectangle->y1, (rectangle->x2 - rectangle->x1), (rectangle->y2 - rectangle->y1));
cairo_rectangle(cairo, scale * rectangle->y1, scale * rectangle->x1, height, width);
break;
case 180:
cairo_rectangle(cairo, scale * (page_width - rectangle->x1) - width, scale * rectangle->y1, width, height);
break;
case 270:
cairo_rectangle(cairo, scale * (page_height - rectangle->y1) - height, scale * (page_width - rectangle->x1) - width, height, width);
break;
default:
cairo_rectangle(cairo, scale * rectangle->x1, scale * (page_height - rectangle->y1) - height, width, height);
}
cairo_fill(cairo); cairo_fill(cairo);
} }
@ -399,6 +422,57 @@ open_link(char* link)
system(start_browser); system(start_browser);
} }
void
save_images(int page, char* directory)
{
GList *image_list;
GList *images;
cairo_surface_t *image;
PopplerPage *document_page;
document_page = poppler_document_get_page(Zathura.PDF.document, page);
image_list = poppler_page_get_image_mapping(document_page);
for(images = image_list; images; images = g_list_next(images))
{
PopplerImageMapping *image_mapping;
PopplerRectangle image_field;
gint image_id;
char* file;
image_mapping = (PopplerImageMapping*) images->data;
image_field = image_mapping->area;
image_id = image_mapping->image_id;
image = poppler_page_get_image(document_page, image_id);
file = g_strdup_printf("%sp%i_i%i.png", directory, page + 1, image_id);
cairo_surface_write_to_png(image, file);
g_free(file);
}
}
void
save_attachments(char* directory)
{
GList *attachment_list;
GList *attachments;
char *file;
attachment_list = poppler_document_get_attachments(Zathura.PDF.document);
for(attachments = attachment_list; attachments; attachments = g_list_next(attachments))
{
PopplerAttachment *attachment = (PopplerAttachment*) attachments->data;
file = g_strdup_printf("%s%s", directory, attachment->name);
poppler_attachment_save(attachment, file, NULL);
g_free(file);
}
}
gboolean gboolean
delete_widget(gpointer data) delete_widget(gpointer data)
{ {
@ -661,6 +735,8 @@ sc_search(Argument *argument)
/* draw results */ /* draw results */
if(results) if(results)
{ {
double page_width, page_height;
poppler_page_get_size(Zathura.PDF.page, &page_width, &page_height);
draw(); draw();
update_notification(GTK_WIDGET(search_status), DEFAULT, g_strdup_printf("%s found on page %i for %i time(s)", update_notification(GTK_WIDGET(search_status), DEFAULT, g_strdup_printf("%s found on page %i for %i time(s)",
@ -668,19 +744,16 @@ sc_search(Argument *argument)
for(list = results; list && list->data; list = g_list_next(list)) for(list = results; list && list->data; list = g_list_next(list))
{ {
highlight_result((PopplerRectangle*) list->data); PopplerRectangle* result = (PopplerRectangle*) list->data;
result->y1 = page_height - result->y1;
result->y2 = page_height - result->y2;
highlight_result(result);
} }
} }
else else
update_notification(search_status, DEFAULT, g_strdup_printf("No match for %s", search_item)); update_notification(search_status, DEFAULT, g_strdup_printf("No match for %s", search_item));
} }
void
sc_print(Argument *argument)
{
}
void void
sc_quit(Argument *argument) sc_quit(Argument *argument)
{ {
@ -719,30 +792,78 @@ cmd_open(int argc, char** argv)
set_page(0); set_page(0);
draw(); draw();
update_status(); update_status();
update_title(); update_title();
} }
void
cmd_print(int argc, char** argv)
{
if(argc == 0 || !Zathura.PDF.document)
return;
char* print_command;
char* sites;
if(strcmp(argv[0], "all") == 0)
sites = g_strdup_printf("%i", Zathura.PDF.number_of_pages);
else
sites = argv[0];
print_command = g_strdup_printf("lp -d '%s' -P %s %s", PRINTER, sites, Zathura.PDF.file);
system(print_command);
}
void void
cmd_export(int argc, char** argv) cmd_export(int argc, char** argv)
{ {
if(argc == 0) if(argc == 0 || !Zathura.PDF.document)
return; return;
if(strcmp(argv[0], "image") == 0) if(argc < 2)
{ {
notify(WARNING, "No export path specified");
return;
} }
else if(strcmp(argv[0], "links") == 0)
/* export images */
if(strcmp(argv[0], "images") == 0)
{ {
int page_counter;
if(argc == 3)
{
int page_number = atoi(argv[2]) - 1;
if(page_number < 0 || page_number > Zathura.PDF.number_of_pages)
notify(WARNING, "Page does not exist");
else
save_images(page_number, argv[1]);
return;
}
for(page_counter = 0; page_counter < Zathura.PDF.number_of_pages; page_counter++)
{
save_images(page_counter, argv[1]);
}
} }
/* export attachments */
else if(strcmp(argv[0], "attachments") == 0) else if(strcmp(argv[0], "attachments") == 0)
{ {
if(!poppler_document_has_attachments(Zathura.PDF.document))
notify(WARNING, "PDF file has no attachments");
else
save_attachments(argv[1]);
}
else
{
notify(DEFAULT, "export [images|attachments]");
return;
} }
} }
void void
@ -889,6 +1010,7 @@ cb_draw(GtkWidget *widget, gpointer data)
void void
cb_destroy(GtkWidget *widget, gpointer data) cb_destroy(GtkWidget *widget, gpointer data)
{ {
pango_font_description_free(Zathura.Settings.font);
gtk_main_quit(); gtk_main_quit();
} }
@ -994,16 +1116,22 @@ cb_drawing_area_button_pressed(GtkWidget* widget, GdkEventButton* event, gpointe
{ {
double page_width, page_height; double page_width, page_height;
poppler_page_get_size(Zathura.PDF.page, &page_width, &page_height); poppler_page_get_size(Zathura.PDF.page, &page_width, &page_height);
PopplerRectangle* link_rectangle = &link_mapping->area;
if(Zathura.PDF.rotate == 0 || Zathura.PDF.rotate == 180)
event->y = page_height - event->y;
else if(Zathura.PDF.rotate == 90 || Zathura.PDF.rotate == 270)
event->x = page_height - event->x;
link_rectangle = recalcRectangle(link_rectangle);
// check if click is in url area // check if click is in url area
if( (link_mapping->area.x1 <= event->x) if( (link_rectangle->x1 <= event->x)
&& (link_mapping->area.x2 >= event->x) && (link_rectangle->x2 >= event->x)
&& (link_mapping->area.y1 <= (page_height - event->y)) && (link_rectangle->y1 <= event->y)
&& (link_mapping->area.y2 >= (page_height - event->y)) && (link_rectangle->y2 >= event->y)
) )
{
open_link(action->uri.uri); open_link(action->uri.uri);
}
} }
} }