diff --git a/ft/pdf-mupdf/Makefile b/ft/pdf-mupdf/Makefile new file mode 100644 index 0000000..e14ed8c --- /dev/null +++ b/ft/pdf-mupdf/Makefile @@ -0,0 +1,51 @@ +# See LICENSE file for license and copyright information + +include config.mk + +PLUGIN = pdf +SOURCE = pdf.c +OBJECTS = ${SOURCE:.c=.o} +DOBJECTS = ${SOURCE:.c=.do} + +all: options ${PLUGIN} + +options: + @echo ${PLUGIN} build options: + @echo "CFLAGS = ${CFLAGS}" + @echo "LDFLAGS = ${LDFLAGS}" + @echo "DFLAGS = ${DFLAGS}" + @echo "CC = ${CC}" + +%.o: %.c + @echo CC $< + @${CC} -c ${CFLAGS} -o $@ $< + +%.do: %.c + @echo CC $< + @${CC} -c ${CFLAGS} ${DFLAGS} -o $@ $< + +${OBJECTS}: config.mk +${DOBJECTS}: config.mk + +${PLUGIN}: ${OBJECTS} + @echo LD $@ + @${CC} -shared ${LDFLAGS} -o ${PLUGIN}.so $(OBJECTS) ${LIBS} + +${PLUGIN}-debug: ${DOBJECTS} + @echo LD $@ + @${CC} -shared ${LDFLAGS} -o ${PLUGIN}.so $(DOBJECTS) ${LIBS} + +clean: + @rm -rf ${OBJECTS} ${DOBJECTS} $(PLUGIN).so + +debug: options ${PLUGIN}-debug + +install: all + @echo installing ${PLUGIN} plugin + @mkdir -p ${DESTDIR}${PREFIX}/lib/zathura + @cp -f ${PLUGIN}.so ${DESTDIR}${PREFIX}/lib/zathura + +uninstall: + @echo uninstalling ${PLUGIN} plugin + @rm -f ${DESTDIR}${PREFIX}/lib/zathura/${PLUGIN}.so + @rm -rf ${DESTDIR}${PREFIX}/lib/zathura diff --git a/ft/pdf-mupdf/config.mk b/ft/pdf-mupdf/config.mk new file mode 100644 index 0000000..9aeb43a --- /dev/null +++ b/ft/pdf-mupdf/config.mk @@ -0,0 +1,21 @@ +# See LICENSE file for license and copyright information + +# paths +PREFIX ?= /usr + +# libs +GTK_INC = $(shell pkg-config --cflags gtk+-2.0) +GTK_LIB = $(shell pkg-config --libs gtk+-2.0) + +INCS = -I. -I/usr/include ${GTK_INC} +LIBS = -lc ${GTK_LIB} -lmupdf -ljbig2dec -ljpeg -lopenjpeg + +# flags +CFLAGS += -std=c99 -fPIC -pedantic -Wall -Wno-format-zero-length $(INCS) + +# debug +DFLAGS = -g + +# compiler +CC ?= gcc +LD ?= ld diff --git a/ft/pdf-mupdf/pdf.c b/ft/pdf-mupdf/pdf.c new file mode 100644 index 0000000..8af67a0 --- /dev/null +++ b/ft/pdf-mupdf/pdf.c @@ -0,0 +1,257 @@ +/* See LICENSE file for license and copyright information */ + +#include + +#include "pdf.h" +#include "../../zathura.h" + +void +plugin_register(zathura_document_plugin_t* plugin) +{ + plugin->file_extension = "pdf"; + plugin->open_function = pdf_document_open; +} + +bool +pdf_document_open(zathura_document_t* document) +{ + if (!document) { + goto error_ret; + } + + document->functions.document_free = pdf_document_free; + document->functions.page_get = pdf_page_get; + document->functions.page_search_text = pdf_page_search_text; + document->functions.page_links_get = pdf_page_links_get; + document->functions.page_form_fields_get = pdf_page_form_fields_get; + document->functions.page_render = pdf_page_render; + document->functions.page_free = pdf_page_free; + + document->data = malloc(sizeof(pdf_document_t)); + if (!document->data) { + goto error_ret; + } + + pdf_document_t* pdf_document = (pdf_document_t*) document->data; + + fz_accelerate(); + pdf_document->glyphcache = fz_newglyphcache(); + + if (pdf_openxref(&(pdf_document->document), document->file_path, NULL)) { + fprintf(stderr, "error: could not open file\n"); + goto error_free; + } + + if (pdf_loadpagetree(pdf_document->document)) { + fprintf(stderr, "error: could not open file\n"); + goto error_free; + } + + document->number_of_pages = pdf_getpagecount(pdf_document->document); + + return true; + +error_free: + + if (pdf_document->document) { + pdf_freexref(pdf_document->document); + } + + if (pdf_document->glyphcache) { + fz_freeglyphcache(pdf_document->glyphcache); + } + + free(document->data); + document->data = NULL; + +error_ret: + + return false; +} + +bool +pdf_document_free(zathura_document_t* document) +{ + if (!document) { + return false; + } + + if (document->data) { + pdf_document_t* pdf_document = (pdf_document_t*) document->data; + pdf_freexref(pdf_document->document); + fz_freeglyphcache(pdf_document->glyphcache); + free(document->data); + document->data = NULL; + } + + return true; +} + +zathura_page_t* +pdf_page_get(zathura_document_t* document, unsigned int page) +{ + if (!document || !document->data) { + return NULL; + } + + pdf_document_t* pdf_document = (pdf_document_t*) document->data; + zathura_page_t* document_page = malloc(sizeof(zathura_page_t)); + + if (document_page == NULL) { + goto error_ret; + } + + mupdf_page_t* mupdf_page = malloc(sizeof(mupdf_page_t)); + + if (mupdf_page == NULL) { + goto error_free; + } + + document_page->document = document; + document_page->data = mupdf_page; + + mupdf_page->page_object = pdf_getpageobject(pdf_document->document, page + 1); + + if (pdf_loadpage(&(mupdf_page->page), pdf_document->document, mupdf_page->page_object)) { + goto error_free; + } + + document_page->width = mupdf_page->page->mediabox.x1 - mupdf_page->page->mediabox.x0; + document_page->height = mupdf_page->page->mediabox.y1 - mupdf_page->page->mediabox.y0; + + return document_page; + +error_free: + + if (mupdf_page && mupdf_page->page_object) { + fz_dropobj(mupdf_page->page_object); + } + + if (mupdf_page && mupdf_page->page) { + pdf_freepage(mupdf_page->page); + } + + free(document_page); + free(mupdf_page); + +error_ret: + + return NULL; +} + +bool +pdf_page_free(zathura_page_t* page) +{ + if (!page) { + return false; + } + + mupdf_page_t* mupdf_page = (mupdf_page_t*) page->data; + pdf_freepage(mupdf_page->page); + fz_dropobj(mupdf_page->page_object); + free(mupdf_page); + free(page); + + return true; +} + +zathura_list_t* +pdf_page_search_text(zathura_page_t* page, const char* text) +{ + return NULL; +} + +zathura_list_t* +pdf_page_links_get(zathura_page_t* page) +{ + return NULL; +} + +zathura_list_t* +pdf_page_form_fields_get(zathura_page_t* page) +{ + return NULL; +} + +GtkWidget* +pdf_page_render(zathura_page_t* page) +{ + if (!Zathura.document || !page || !page->data || !page->document) { + return NULL; + } + + /* calculate sizes */ + unsigned int page_width = Zathura.document->scale * page->width; + unsigned int page_height = Zathura.document->scale * page->height; + + if (Zathura.document->rotate == 90 || Zathura.document->rotate == 270) { + unsigned int dim_temp = 0; + dim_temp = page_width; + page_width = page_height; + page_height = dim_temp; + } + + /* create pixbuf */ + GdkPixbuf* pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, + page_width, page_height); + + if (!pixbuf) { + return NULL; + } + + pdf_document_t* pdf_document = (pdf_document_t*) page->document->data; + mupdf_page_t* mupdf_page = (mupdf_page_t*) page->data; + + /* render */ + fz_displaylist* display_list = fz_newdisplaylist(); + fz_device* device = fz_newlistdevice(display_list); + + if (pdf_runpage(pdf_document->document, mupdf_page->page, device, fz_identity)) { + return NULL; + } + + fz_freedevice(device); + + fz_matrix ctm = fz_translate(0, -mupdf_page->page->mediabox.y1); + ctm = fz_concat(ctm, fz_scale(Zathura.document->scale, -Zathura.document->scale)); + fz_bbox bbox = fz_roundrect(fz_transformrect(ctm, mupdf_page->page->mediabox)); + + guchar* pixels = gdk_pixbuf_get_pixels(pixbuf); + int rowstride = gdk_pixbuf_get_rowstride(pixbuf); + int n_channels = gdk_pixbuf_get_n_channels(pixbuf); + + fz_pixmap* pixmap = fz_newpixmapwithrect(fz_devicergb, bbox); + fz_clearpixmapwithcolor(pixmap, 0xFF); + + device = fz_newdrawdevice(pdf_document->glyphcache, pixmap); + fz_executedisplaylist(display_list, device, ctm); + fz_freedevice(device); + + for (unsigned int y = 0; y < pixmap->h; y++) { + for (unsigned int x = 0; x < pixmap->w; x++) { + unsigned char *s = pixmap->samples + y * pixmap->w * 4 + x * 4; + guchar* p = pixels + y * rowstride + x * n_channels; + p[0] = s[0]; + p[1] = s[1]; + p[2] = s[2]; + } + } + + fz_droppixmap(pixmap); + fz_freedisplaylist(display_list); + pdf_freepage(mupdf_page->page); + pdf_agestore(pdf_document->document->store, 3); + + /* write pixbuf */ + GtkWidget* image = gtk_image_new(); + + if (!image) { + g_object_unref(pixbuf); + return NULL; + } + + gtk_image_set_from_pixbuf(GTK_IMAGE(image), pixbuf); + gtk_widget_show(image); + + return image; +} diff --git a/ft/pdf-mupdf/pdf.h b/ft/pdf-mupdf/pdf.h new file mode 100644 index 0000000..9d53949 --- /dev/null +++ b/ft/pdf-mupdf/pdf.h @@ -0,0 +1,33 @@ +/* See LICENSE file for license and copyright information */ + +#ifndef PDF_H +#define PDF_H + +#include +#include +#include + +#include "../../document.h" + +typedef struct pdf_document_s +{ + fz_glyphcache *glyphcache; + pdf_xref *document; +} pdf_document_t; + +typedef struct mupdf_page_s +{ + fz_obj* page_object; + pdf_page* page; +} mupdf_page_t; + +bool pdf_document_open(zathura_document_t* document); +bool pdf_document_free(zathura_document_t* document); +zathura_page_t* pdf_page_get(zathura_document_t* document, unsigned int page); +zathura_list_t* pdf_page_search_text(zathura_page_t* page, const char* text); +zathura_list_t* pdf_page_links_get(zathura_page_t* page); +zathura_list_t* pdf_page_form_fields_get(zathura_page_t* page); +GtkWidget* pdf_page_render(zathura_page_t* page); +bool pdf_page_free(zathura_page_t* page); + +#endif // PDF_H