236 行
6.7 KiB
C
236 行
6.7 KiB
C
|
#include <X11/Xlib.h>
|
|||
|
#include <X11/Xutil.h>
|
|||
|
#include <poppler/glib/poppler.h>
|
|||
|
#include <X11/keysym.h>
|
|||
|
#include <cairo/cairo.h>
|
|||
|
#include <cairo/cairo-xlib.h>
|
|||
|
#include <stdio.h>
|
|||
|
#include <ctype.h>
|
|||
|
#include <stdbool.h>
|
|||
|
|
|||
|
PopplerDocument *doc = NULL;
|
|||
|
int curpage = 0;
|
|||
|
int totpage = 0;
|
|||
|
//char sq[256] = {0}; // TODO: 検索
|
|||
|
|
|||
|
void cairo_surface_clear(cairo_surface_t *surface) {
|
|||
|
cairo_t *cr = cairo_create(surface);
|
|||
|
cairo_set_source_rgba(cr, 0, 0, 0, 0);
|
|||
|
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
|
|||
|
cairo_paint(cr);
|
|||
|
cairo_destroy(cr);
|
|||
|
}
|
|||
|
|
|||
|
// TODO: 検索
|
|||
|
/*void search(PopplerDocument *doc, const char *keyword, cairo_t *cr) {
|
|||
|
int n_page = poppler_document_get_n_pages(doc);
|
|||
|
|
|||
|
for (int i = 0; i < n_page; i++) {
|
|||
|
PopplerPage *page = poppler_document_get_page(doc, i);
|
|||
|
if (!page) continue;
|
|||
|
|
|||
|
GList *matches = poppler_page_find_text(page, keyword);
|
|||
|
for (GList *l = matches; l; l = l->next) {
|
|||
|
PopplerRectangle *match = (PopplerRectangle *)l->data;
|
|||
|
|
|||
|
cairo_set_source_rgba(cr, 1, 1, 0, 0.5);
|
|||
|
cairo_rectangle(cr, match->x1, match->y1, match->x2 - match->x1, match->y2 - match->y1);
|
|||
|
cairo_fill(cr);
|
|||
|
|
|||
|
poppler_rectangle_free(match);
|
|||
|
}
|
|||
|
g_list_free(matches);
|
|||
|
g_object_unref(page);
|
|||
|
}
|
|||
|
}*/
|
|||
|
|
|||
|
void open_pdf(const char* filename) {
|
|||
|
GError *error = NULL;
|
|||
|
char file_uri[512];
|
|||
|
snprintf(file_uri, sizeof(file_uri), "file://%s", filename);
|
|||
|
doc = poppler_document_new_from_file(file_uri, NULL, &error);
|
|||
|
if (doc == NULL) {
|
|||
|
printf("PDFファイルを読み込みに失敗しました: %s\n", error->message);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
curpage = 0;
|
|||
|
totpage = poppler_document_get_n_pages(doc);
|
|||
|
|
|||
|
PopplerPage *page = poppler_document_get_page(doc, curpage);
|
|||
|
if (page == NULL) {
|
|||
|
printf("ページを読み込みに失敗しました。\n");
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
double pag_w, pag_h;
|
|||
|
poppler_page_get_size(page, &pag_w, &pag_h);
|
|||
|
|
|||
|
Display *d = XOpenDisplay(NULL);
|
|||
|
Window w = XCreateSimpleWindow(d, RootWindow(d, 0), 0, 0, pag_w, pag_h, 1, 0, 0);
|
|||
|
XSelectInput(d, w, ExposureMask | KeyPressMask | StructureNotifyMask);
|
|||
|
XMapWindow(d, w);
|
|||
|
|
|||
|
cairo_surface_t *xlib_surface = cairo_xlib_surface_create(d, w, DefaultVisual(d, 0), pag_w, pag_h);
|
|||
|
cairo_t *xlib_cr = cairo_create(xlib_surface);
|
|||
|
|
|||
|
double scale = 1.2;
|
|||
|
double xpos = 0.0;
|
|||
|
double ypos = 0.0;
|
|||
|
// TODO: 検索
|
|||
|
//bool isfind = false;
|
|||
|
//int sqlen = 0;
|
|||
|
|
|||
|
while (1) {
|
|||
|
XEvent e;
|
|||
|
XNextEvent(d, &e);
|
|||
|
|
|||
|
if (e.type == KeyPress) {
|
|||
|
XWindowAttributes attrs;
|
|||
|
XGetWindowAttributes(d, w, &attrs);
|
|||
|
|
|||
|
KeySym keysym = XLookupKeysym(&e.xkey, 0);
|
|||
|
double pscale = scale;
|
|||
|
|
|||
|
if (keysym == XK_q) {
|
|||
|
break;
|
|||
|
} else if (keysym == XK_plus || keysym == XK_semicolon) {
|
|||
|
scale += 0.1;
|
|||
|
if (scale > 5.0) scale = 5.0;
|
|||
|
xpos -= (pag_w * scale - pag_w * pscale) / 2.0;
|
|||
|
ypos -= (pag_h * scale - pag_h * pscale) / 2.0;
|
|||
|
} else if (keysym == XK_minus || keysym == XK_equal) {
|
|||
|
scale -= 0.1;
|
|||
|
if (scale < 0.1) scale = 0.1;
|
|||
|
xpos += (pag_w * pscale - pag_w * scale) / 2.0;
|
|||
|
ypos += (pag_h * pscale - pag_h * scale) / 2.0;
|
|||
|
} else if (keysym == XK_h) {
|
|||
|
xpos -= 10.0;
|
|||
|
if (xpos < 0) xpos = 0;
|
|||
|
} else if (keysym == XK_l) {
|
|||
|
xpos += 10.0;
|
|||
|
if (xpos > pag_w * scale - attrs.width) xpos = pag_w * scale - attrs.width;
|
|||
|
} else if (keysym == XK_k) {
|
|||
|
ypos -= 10.0;
|
|||
|
if (ypos < 0) ypos = 0;
|
|||
|
} else if (keysym == XK_j) {
|
|||
|
ypos += 10.0;
|
|||
|
if (ypos > pag_h * scale - attrs.height) ypos = pag_h * scale - attrs.height;
|
|||
|
} else if (keysym == XK_comma || keysym == XK_less) {
|
|||
|
if (curpage > 0) {
|
|||
|
curpage--;
|
|||
|
if (curpage < 0) curpage = 0;
|
|||
|
xpos = 0.0;
|
|||
|
ypos = 0.0;
|
|||
|
page = poppler_document_get_page(doc, curpage);
|
|||
|
}
|
|||
|
} else if (keysym == XK_period || keysym == XK_greater) {
|
|||
|
if (curpage < totpage - 1) {
|
|||
|
curpage++;
|
|||
|
if (curpage >= totpage) curpage = totpage - 1;
|
|||
|
xpos = 0.0;
|
|||
|
ypos = 0.0;
|
|||
|
page = poppler_document_get_page(doc, curpage);
|
|||
|
}
|
|||
|
// TODO: 検索
|
|||
|
/*} else if (keysym == XK_slash) {
|
|||
|
if (!isfind) {
|
|||
|
isfind = true;
|
|||
|
memset(sq, 0, sizeof(sq));
|
|||
|
sqlen = 0;
|
|||
|
}
|
|||
|
continue;
|
|||
|
} else if (keysym == XK_Escape) {
|
|||
|
if (isfind) {
|
|||
|
isfind = false;
|
|||
|
memset(sq, 0, sizeof(sq));
|
|||
|
sqlen = 0;
|
|||
|
continue;
|
|||
|
}*/
|
|||
|
}
|
|||
|
|
|||
|
// TODO: 検索
|
|||
|
/*if (isfind) {
|
|||
|
char str[25];
|
|||
|
int len = XLookupString(&e.xkey, str, sizeof(str), NULL, NULL);
|
|||
|
if (len > 0 && sqlen + len < sizeof(sq) - 1) {
|
|||
|
strncpy(sq + sqlen, str, len);
|
|||
|
sqlen += len;
|
|||
|
sq[sqlen] = '\0';
|
|||
|
search(doc, sq, xlib_cr);
|
|||
|
} else if (keysym == XK_BackSpace && sqlen > 0) {
|
|||
|
sq[--sqlen] = '\0';
|
|||
|
search(doc, sq, xlib_cr);
|
|||
|
}
|
|||
|
continue;
|
|||
|
}*/
|
|||
|
|
|||
|
XClearWindow(d, w);
|
|||
|
XExposeEvent ev = {0};
|
|||
|
ev.type = Expose;
|
|||
|
ev.window = w;
|
|||
|
XSendEvent(d, w, False, ExposureMask, (XEvent*)&ev);
|
|||
|
XFlush(d);
|
|||
|
}
|
|||
|
|
|||
|
if (e.type == ConfigureNotify) {
|
|||
|
pag_w = e.xconfigure.width;
|
|||
|
pag_h = e.xconfigure.height;
|
|||
|
cairo_xlib_surface_set_size(xlib_surface, pag_w, pag_h);
|
|||
|
}
|
|||
|
|
|||
|
if (e.type == Expose) {
|
|||
|
XWindowAttributes attrs;
|
|||
|
XGetWindowAttributes(d, w, &attrs);
|
|||
|
|
|||
|
// 表示を削除
|
|||
|
cairo_identity_matrix(xlib_cr);
|
|||
|
cairo_set_source_rgb(xlib_cr, 1, 1, 1);
|
|||
|
cairo_paint(xlib_cr);
|
|||
|
|
|||
|
// 表示を作成
|
|||
|
cairo_translate(xlib_cr, xpos, ypos);
|
|||
|
cairo_scale(xlib_cr, scale, scale);
|
|||
|
|
|||
|
// TODO: ページ番号の表示
|
|||
|
/*cairo_identity_matrix(xlib_cr);
|
|||
|
char pinf[100];
|
|||
|
snprintf(pinf, sizeof(pinf), "%d/%dページ", curpage + 1, totpage);
|
|||
|
cairo_text_extents_t te;
|
|||
|
cairo_select_font_face(xlib_cr, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
|
|||
|
cairo_set_font_size(xlib_cr, 14);
|
|||
|
cairo_text_extents(xlib_cr, pinf, &te);
|
|||
|
cairo_move_to(xlib_cr, 10, 20);
|
|||
|
cairo_set_source_rgb(xlib_cr, 0, 0, 0);
|
|||
|
cairo_show_text(xlib_cr, pinf);*/
|
|||
|
|
|||
|
cairo_status_t status = cairo_status(xlib_cr);
|
|||
|
if (status != CAIRO_STATUS_SUCCESS) {
|
|||
|
fprintf(stderr, "Cairoエラー: %s\n", cairo_status_to_string(status));
|
|||
|
}
|
|||
|
|
|||
|
// TODO: 検索
|
|||
|
//search(doc, sq, xlib_cr);
|
|||
|
poppler_page_render(page, xlib_cr);
|
|||
|
cairo_surface_flush(xlib_surface);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
cairo_destroy(xlib_cr);
|
|||
|
cairo_surface_destroy(xlib_surface);
|
|||
|
g_object_unref(page);
|
|||
|
g_object_unref(doc);
|
|||
|
XCloseDisplay(d);
|
|||
|
}
|
|||
|
|
|||
|
int main(int argc, char **argv) {
|
|||
|
if (argc < 2) {
|
|||
|
g_print("使用方法: %s <PDFファイル>\n", argv[0]);
|
|||
|
return 1;
|
|||
|
}
|
|||
|
|
|||
|
open_pdf(argv[1]);
|
|||
|
|
|||
|
return 0;
|
|||
|
}
|