diff --git a/Makefile b/Makefile index 081f825a0..b92c0c7e9 100644 --- a/Makefile +++ b/Makefile @@ -109,7 +109,7 @@ LUALIB := $(LUADIR)/src/libluajit.a POPENNSLIB := $(POPENNSDIR)/libpopen_noshell.a -all: kpdfview +all: kpdfview extr VERSION?=$(shell git describe HEAD) kpdfview: kpdfview.o einkfb.o pdf.o k2pdfopt.o blitbuffer.o drawcontext.o input.o $(POPENNSLIB) util.o ft.o lfs.o mupdfimg.o $(MUPDFLIBS) $(THIRDPARTYLIBS) $(LUALIB) djvu.o $(DJVULIBS) cre.o $(CRENGINELIBS) pic.o pic_jpeg.o @@ -144,6 +144,12 @@ kpdfview: kpdfview.o einkfb.o pdf.o k2pdfopt.o blitbuffer.o drawcontext.o input. $(EMU_LDFLAGS) \ $(DYNAMICLIBSTDCPP) +extr: extr.o + $(CC) $(CFLAGS) extr.o $(MUPDFLIBS) $(THIRDPARTYLIBS) -lm -o extr + +extr.o: %.o: %.c + $(CC) -c -I$(MUPDFDIR)/pdf -I$(MUPDFDIR)/fitz $< -o $@ + slider_watcher.o: %.o: %.c $(CC) -c $(CFLAGS) $< -o $@ @@ -207,7 +213,7 @@ fetchthirdparty: cd popen-noshell && test -f Makefile || patch -N -p0 < popen_noshell-buildfix.patch clean: - rm -f *.o kpdfview slider_watcher + rm -f *.o kpdfview slider_watcher extr cleanthirdparty: $(MAKE) -C $(LUADIR) CC="$(HOSTCC)" CFLAGS="$(BASE_CFLAGS)" clean @@ -268,13 +274,14 @@ INSTALL_DIR=kindlepdfviewer LUA_FILES=reader.lua customupdate: all - # ensure that build binary is for ARM + # ensure that the binaries were built for ARM file kpdfview | grep ARM || exit 1 - $(STRIP) --strip-unneeded kpdfview + file extr | grep ARM || exit 1 + $(STRIP) --strip-unneeded kpdfview extr rm -f kindlepdfviewer-$(VERSION).zip rm -rf $(INSTALL_DIR) mkdir -p $(INSTALL_DIR)/{history,screenshots} - cp -p README.md COPYING kpdfview kpdf.sh $(LUA_FILES) $(INSTALL_DIR) + cp -p README.md COPYING kpdfview extr kpdf.sh $(LUA_FILES) $(INSTALL_DIR) mkdir $(INSTALL_DIR)/data cp -rpL data/*.css $(INSTALL_DIR)/data cp -rpL fonts $(INSTALL_DIR) diff --git a/extr.c b/extr.c new file mode 100644 index 000000000..c41debee6 --- /dev/null +++ b/extr.c @@ -0,0 +1,106 @@ +/* + extr: Extract attachments from PDF file + + Usage: extr /dir/file.pdf pageno + Returns 0 if one or more attachments saved, otherwise returns non-zero. + Prints the number of saved attachments on stdout. + Attachments are saved in /dir directory with the appropriate filenames. + + Copyright (C) 2012 Tigran Aivazian + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "mupdf-internal.h" +#include + +/* doc is shared between save_attachments() and dump_stream() */ +static pdf_document *doc; + +void dump_stream(int i, FILE *fout) +{ + fz_stream *stm = pdf_open_stream(doc, i, 0); + static unsigned char buf[8192]; + while (1) { + int n = fz_read(stm, buf, sizeof buf); + if (n == 0) break; + fwrite(buf, 1, n, fout); + } + fz_close(stm); +} + +/* returns the number of attachments saved */ +int save_attachments(int pageno, char *targetdir) +{ + pdf_page *page = pdf_load_page(doc, pageno-1); + pdf_annot *annot; + int saved_count = 0; + + for (annot = page->annots; annot ; annot = annot->next) { + pdf_obj *fs_obj = pdf_dict_gets(annot->obj, "FS"); + if (fs_obj) { + pdf_obj *ef_obj; + char *name = pdf_to_str_buf(pdf_dict_gets(fs_obj, "F")); + ef_obj = pdf_dict_gets(fs_obj, "EF"); + if (ef_obj) { + pdf_obj *f_obj = pdf_dict_gets(ef_obj, "F"); + if (f_obj && pdf_is_indirect(f_obj)) { + static char pathname[PATH_MAX]; + sprintf(pathname, "%s/%s", targetdir, name); + FILE *fout = fopen(pathname, "w"); + if (!fout) { + fprintf(stderr, "extr: cannot write to file %s\n", name); + exit(1); + } + dump_stream(pdf_to_num(f_obj), fout); + fclose(fout); + saved_count++; + } + } + } + } + return saved_count; +} + +int main(int argc, char *argv[]) +{ + int saved = 0; + + if (argc != 3) { + printf("Usage: extr file.pdf pageno\n"); + exit(1); + } + + char *filename = strdup(argv[1]); + char *dir = dirname(strdup(filename)); + int pageno = atoi(argv[2]); + + fz_context *ctx = fz_new_context(NULL, NULL, FZ_STORE_UNLIMITED); + if (!ctx) { + fprintf(stderr, "extr: cannot create context\n"); + exit(1); + } + + fz_var(doc); + fz_try(ctx) { + doc = pdf_open_document(ctx, filename); + saved = save_attachments(pageno, dir); + } + fz_catch(ctx) + { + } + + printf("%d\n", saved); + return 0; +}