summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--include/mupdf/fitz.h1
-rw-r--r--include/mupdf/fitz/buffer.h2
-rw-r--r--include/mupdf/fitz/output.h10
-rw-r--r--include/mupdf/fitz/unzip.h6
-rw-r--r--include/mupdf/fitz/writer.h28
-rw-r--r--source/fitz/buffer.c14
-rw-r--r--source/fitz/output-cbz.c94
-rw-r--r--source/fitz/writer.c38
-rw-r--r--source/fitz/zip.c112
-rw-r--r--source/tools/muconvert.c141
-rw-r--r--source/tools/mutool.c3
12 files changed, 449 insertions, 2 deletions
diff --git a/Makefile b/Makefile
index 074ef2eb..64726a9f 100644
--- a/Makefile
+++ b/Makefile
@@ -255,7 +255,7 @@ $(OUT)/cmapdump.o : include/mupdf/pdf/cmap.h source/pdf/pdf-cmap.c source/pdf/pd
# --- Tools and Apps ---
MUTOOL := $(addprefix $(OUT)/, mutool)
-MUTOOL_OBJ := $(addprefix $(OUT)/tools/, mutool.o mudraw.o murun.o pdfclean.o pdfcreate.o pdfextract.o pdfinfo.o pdfposter.o pdfshow.o pdfpages.o pdfmerge.o)
+MUTOOL_OBJ := $(addprefix $(OUT)/tools/, mutool.o muconvert.o mudraw.o murun.o pdfclean.o pdfcreate.o pdfextract.o pdfinfo.o pdfmerge.o pdfposter.o pdfpages.o pdfshow.o)
$(MUTOOL_OBJ): $(FITZ_HDR) $(PDF_HDR)
$(MUTOOL) : $(MUPDF_LIB) $(THIRD_LIB)
$(MUTOOL) : $(MUTOOL_OBJ)
diff --git a/include/mupdf/fitz.h b/include/mupdf/fitz.h
index ec0c87a4..6f4e431d 100644
--- a/include/mupdf/fitz.h
+++ b/include/mupdf/fitz.h
@@ -58,6 +58,7 @@ extern "C" {
#include "mupdf/fitz/util.h"
/* Output formats */
+#include "mupdf/fitz/writer.h"
#include "mupdf/fitz/output-pnm.h"
#include "mupdf/fitz/output-png.h"
#include "mupdf/fitz/output-pwg.h"
diff --git a/include/mupdf/fitz/buffer.h b/include/mupdf/fitz/buffer.h
index 2749c32c..1a8eb80c 100644
--- a/include/mupdf/fitz/buffer.h
+++ b/include/mupdf/fitz/buffer.h
@@ -130,6 +130,8 @@ void fz_append_buffer(fz_context *ctx, fz_buffer *buf, fz_buffer *extra);
void fz_write_buffer(fz_context *ctx, fz_buffer *buf, const void *data, int len);
void fz_write_buffer_byte(fz_context *ctx, fz_buffer *buf, int val);
void fz_write_buffer_rune(fz_context *ctx, fz_buffer *buf, int val);
+void fz_write_buffer_int32_le(fz_context *ctx, fz_buffer *buf, int x);
+void fz_write_buffer_int16_le(fz_context *ctx, fz_buffer *buf, int x);
void fz_write_buffer_bits(fz_context *ctx, fz_buffer *buf, int val, int bits);
void fz_write_buffer_pad(fz_context *ctx, fz_buffer *buf);
int fz_buffer_printf(fz_context *ctx, fz_buffer *buffer, const char *fmt, ...);
diff --git a/include/mupdf/fitz/output.h b/include/mupdf/fitz/output.h
index 8b59d386..35f61aa7 100644
--- a/include/mupdf/fitz/output.h
+++ b/include/mupdf/fitz/output.h
@@ -97,6 +97,16 @@ static inline void fz_write_int32_le(fz_context *ctx, fz_output *out, int x)
fz_write(ctx, out, data, 4);
}
+static inline void fz_write_int16_le(fz_context *ctx, fz_output *out, int x)
+{
+ char data[2];
+
+ data[0] = x;
+ data[1] = x>>8;
+
+ fz_write(ctx, out, data, 2);
+}
+
static inline void fz_write_byte(fz_context *ctx, fz_output *out, unsigned char x)
{
fz_write(ctx, out, &x, 1);
diff --git a/include/mupdf/fitz/unzip.h b/include/mupdf/fitz/unzip.h
index b19ffbd9..64b2b94b 100644
--- a/include/mupdf/fitz/unzip.h
+++ b/include/mupdf/fitz/unzip.h
@@ -19,4 +19,10 @@ void fz_drop_archive(fz_context *ctx, fz_archive *ar);
int fz_count_archive_entries(fz_context *ctx, fz_archive *zip);
const char *fz_list_archive_entry(fz_context *ctx, fz_archive *zip, int idx);
+typedef struct fz_zip_writer_s fz_zip_writer;
+
+fz_zip_writer *fz_new_zip_writer(fz_context *ctx, const char *filename);
+void fz_write_zip_entry(fz_context *ctx, fz_zip_writer *zip, const char *name, fz_buffer *buf, int compress);
+void fz_drop_zip_writer(fz_context *ctx, fz_zip_writer *zip);
+
#endif
diff --git a/include/mupdf/fitz/writer.h b/include/mupdf/fitz/writer.h
new file mode 100644
index 00000000..e318568e
--- /dev/null
+++ b/include/mupdf/fitz/writer.h
@@ -0,0 +1,28 @@
+#ifndef MUPDF_FITZ_WRITER_H
+#define MUPDF_FITZ_WRITER_H
+
+#include "mupdf/fitz/system.h"
+#include "mupdf/fitz/context.h"
+#include "mupdf/fitz/output.h"
+#include "mupdf/fitz/document.h"
+#include "mupdf/fitz/device.h"
+
+typedef struct fz_document_writer_s fz_document_writer;
+
+struct fz_document_writer_s
+{
+ fz_device *(*begin_page)(fz_context *ctx, fz_document_writer *wri, const fz_rect *mediabox, fz_matrix *ctm);
+ void (*end_page)(fz_context *ctx, fz_document_writer *wri, fz_device *dev);
+ void (*drop_imp)(fz_context *ctx, fz_document_writer *wri);
+};
+
+fz_document_writer *fz_new_document_writer(fz_context *ctx, const char *path, const char *format, const char *options);
+
+fz_device *fz_begin_page(fz_context *ctx, fz_document_writer *wri, const fz_rect *mediabox, fz_matrix *ctm);
+void fz_end_page(fz_context *ctx, fz_document_writer *wri, fz_device *dev);
+void fz_drop_document_writer(fz_context *ctx, fz_document_writer *wri);
+
+fz_document_writer *fz_new_cbz_writer(fz_context *ctx, const char *path, const char *options);
+fz_document_writer *fz_new_pdf_writer(fz_context *ctx, const char *path, const char *options);
+
+#endif
diff --git a/source/fitz/buffer.c b/source/fitz/buffer.c
index 2d6f9932..4cff8715 100644
--- a/source/fitz/buffer.c
+++ b/source/fitz/buffer.c
@@ -197,6 +197,20 @@ void fz_write_buffer_rune(fz_context *ctx, fz_buffer *buf, int c)
buf->unused_bits = 0;
}
+void fz_write_buffer_int32_le(fz_context *ctx, fz_buffer *buf, int x)
+{
+ fz_write_buffer_byte(ctx, buf, (x)&0xFF);
+ fz_write_buffer_byte(ctx, buf, (x>>8)&0xFF);
+ fz_write_buffer_byte(ctx, buf, (x>>16)&0xFF);
+ fz_write_buffer_byte(ctx, buf, (x>>24)&0xFF);
+}
+
+void fz_write_buffer_int16_le(fz_context *ctx, fz_buffer *buf, int x)
+{
+ fz_write_buffer_byte(ctx, buf, (x)&0xFF);
+ fz_write_buffer_byte(ctx, buf, (x>>8)&0xFF);
+}
+
void fz_write_buffer_bits(fz_context *ctx, fz_buffer *buf, int val, int bits)
{
int shift;
diff --git a/source/fitz/output-cbz.c b/source/fitz/output-cbz.c
new file mode 100644
index 00000000..df5c0640
--- /dev/null
+++ b/source/fitz/output-cbz.c
@@ -0,0 +1,94 @@
+#include "mupdf/fitz.h"
+
+#include <zlib.h>
+
+typedef struct fz_cbz_writer_s fz_cbz_writer;
+
+struct fz_cbz_writer_s
+{
+ fz_document_writer super;
+ fz_zip_writer *zip;
+ int resolution;
+ fz_pixmap *pixmap;
+ int count;
+};
+
+static fz_device *
+cbz_begin_page(fz_context *ctx, fz_document_writer *wri_, const fz_rect *mediabox, fz_matrix *ctm)
+{
+ fz_cbz_writer *wri = (fz_cbz_writer*)wri_;
+ fz_rect bbox;
+ fz_irect ibbox;
+
+ fz_scale(ctm, wri->resolution / 72, wri->resolution / 72);
+ bbox = *mediabox;
+ fz_transform_rect(&bbox, ctm);
+ fz_round_rect(&ibbox, &bbox);
+
+ wri->pixmap = fz_new_pixmap_with_bbox(ctx, fz_device_rgb(ctx), &ibbox);
+ fz_clear_pixmap_with_value(ctx, wri->pixmap, 0xFF);
+
+ return fz_new_draw_device(ctx, wri->pixmap);
+}
+
+static void
+cbz_end_page(fz_context *ctx, fz_document_writer *wri_, fz_device *dev)
+{
+ fz_cbz_writer *wri = (fz_cbz_writer*)wri_;
+ fz_buffer *buffer;
+ char name[40];
+
+ wri->count += 1;
+
+ fz_snprintf(name, sizeof name, "p%04d.png", wri->count);
+
+ buffer = fz_new_buffer_from_pixmap_as_png(ctx, wri->pixmap);
+ fz_try(ctx)
+ fz_write_zip_entry(ctx, wri->zip, name, buffer, 0);
+ fz_always(ctx)
+ fz_drop_buffer(ctx, buffer);
+ fz_catch(ctx)
+ fz_rethrow(ctx);
+
+ fz_drop_pixmap(ctx, wri->pixmap);
+ wri->pixmap = NULL;
+}
+
+static void
+cbz_drop_imp(fz_context *ctx, fz_document_writer *wri_)
+{
+ fz_cbz_writer *wri = (fz_cbz_writer*)wri_;
+ fz_try(ctx)
+ fz_drop_zip_writer(ctx, wri->zip);
+ fz_always(ctx)
+ fz_drop_pixmap(ctx, wri->pixmap);
+ fz_catch(ctx)
+ fz_rethrow(ctx);
+}
+
+fz_document_writer *
+fz_new_cbz_writer(fz_context *ctx, const char *path, const char *options)
+{
+ fz_cbz_writer *wri = fz_malloc_struct(ctx, fz_cbz_writer);
+
+ wri->super.begin_page = cbz_begin_page;
+ wri->super.end_page = cbz_end_page;
+ wri->super.drop_imp = cbz_drop_imp;
+
+ fz_try(ctx)
+ wri->zip = fz_new_zip_writer(ctx, path);
+ fz_catch(ctx)
+ {
+ fz_free(ctx, wri);
+ fz_rethrow(ctx);
+ }
+
+ // TODO: getopt-like comma separated list of options
+ if (options)
+ wri->resolution = atoi(options);
+
+ if (wri->resolution == 0)
+ wri->resolution = 96;
+
+ return (fz_document_writer*)wri;
+}
diff --git a/source/fitz/writer.c b/source/fitz/writer.c
new file mode 100644
index 00000000..a127a47d
--- /dev/null
+++ b/source/fitz/writer.c
@@ -0,0 +1,38 @@
+#include "mupdf/fitz.h"
+
+fz_document_writer *
+fz_new_document_writer(fz_context *ctx, const char *path, const char *format, const char *options)
+{
+ if (!format)
+ {
+ format = strrchr(path, '.');
+ if (!format)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "cannot detect document format");
+ format += 1; /* skip the '.' */
+ }
+
+ if (!strcasecmp(format, "cbz"))
+ return fz_new_cbz_writer(ctx, path, options);
+
+ fz_throw(ctx, FZ_ERROR_GENERIC, "unknown document format: %s", format);
+}
+
+void
+fz_drop_document_writer(fz_context *ctx, fz_document_writer *wri)
+{
+ if (wri->drop_imp)
+ wri->drop_imp(ctx, wri);
+ fz_free(ctx, wri);
+}
+
+fz_device *
+fz_begin_page(fz_context *ctx, fz_document_writer *wri, const fz_rect *mediabox, fz_matrix *ctm)
+{
+ return wri->begin_page(ctx, wri, mediabox, ctm);
+}
+
+void
+fz_end_page(fz_context *ctx, fz_document_writer *wri, fz_device *dev)
+{
+ return wri->end_page(ctx, wri, dev);
+}
diff --git a/source/fitz/zip.c b/source/fitz/zip.c
new file mode 100644
index 00000000..285fb635
--- /dev/null
+++ b/source/fitz/zip.c
@@ -0,0 +1,112 @@
+#include "mupdf/fitz.h"
+
+#include <zlib.h>
+
+#if !defined (INT32_MAX)
+#define INT32_MAX 2147483647L
+#endif
+
+#define ZIP_LOCAL_FILE_SIG 0x04034b50
+#define ZIP_CENTRAL_DIRECTORY_SIG 0x02014b50
+#define ZIP_END_OF_CENTRAL_DIRECTORY_SIG 0x06054b50
+
+struct fz_zip_writer_s
+{
+ fz_output *output;
+ fz_buffer *central;
+ int count;
+};
+
+void
+fz_write_zip_entry(fz_context *ctx, fz_zip_writer *zip, const char *name, fz_buffer *buf, int compress)
+{
+ int offset = fz_tell_output(ctx, zip->output);
+ int sum;
+
+ sum = crc32(0, NULL, 0);
+ sum = crc32(sum, buf->data, buf->len);
+
+ fz_write_buffer_int32_le(ctx, zip->central, ZIP_CENTRAL_DIRECTORY_SIG);
+ fz_write_buffer_int16_le(ctx, zip->central, 0); /* version made by: MS-DOS */
+ fz_write_buffer_int16_le(ctx, zip->central, 20); /* version to extract: 2.0 */
+ fz_write_buffer_int16_le(ctx, zip->central, 0); /* general purpose bit flag */
+ fz_write_buffer_int16_le(ctx, zip->central, 0); /* compression method: store */
+ fz_write_buffer_int16_le(ctx, zip->central, 0); /* TODO: last mod file time */
+ fz_write_buffer_int16_le(ctx, zip->central, 0); /* TODO: last mod file date */
+ fz_write_buffer_int32_le(ctx, zip->central, sum); /* crc-32 */
+ fz_write_buffer_int32_le(ctx, zip->central, buf->len); /* csize */
+ fz_write_buffer_int32_le(ctx, zip->central, buf->len); /* usize */
+ fz_write_buffer_int16_le(ctx, zip->central, strlen(name)); /* file name length */
+ fz_write_buffer_int16_le(ctx, zip->central, 0); /* extra field length */
+ fz_write_buffer_int16_le(ctx, zip->central, 0); /* file comment length */
+ fz_write_buffer_int16_le(ctx, zip->central, 0); /* disk number start */
+ fz_write_buffer_int16_le(ctx, zip->central, 0); /* internal file attributes */
+ fz_write_buffer_int32_le(ctx, zip->central, 0); /* external file attributes */
+ fz_write_buffer_int32_le(ctx, zip->central, offset); /* relative offset of local header */
+ fz_write_buffer(ctx, zip->central, name, strlen(name));
+
+ fz_write_int32_le(ctx, zip->output, ZIP_LOCAL_FILE_SIG);
+ fz_write_int16_le(ctx, zip->output, 20); /* version to extract: 2.0 */
+ fz_write_int16_le(ctx, zip->output, 0); /* general purpose bit flag */
+ fz_write_int16_le(ctx, zip->output, 0); /* compression method: store */
+ fz_write_int16_le(ctx, zip->output, 0); /* TODO: last mod file time */
+ fz_write_int16_le(ctx, zip->output, 0); /* TODO: last mod file date */
+ fz_write_int32_le(ctx, zip->output, sum); /* crc-32 */
+ fz_write_int32_le(ctx, zip->output, buf->len); /* csize */
+ fz_write_int32_le(ctx, zip->output, buf->len); /* usize */
+ fz_write_int16_le(ctx, zip->output, strlen(name)); /* file name length */
+ fz_write_int16_le(ctx, zip->output, 0); /* extra field length */
+ fz_write(ctx, zip->output, name, strlen(name));
+ fz_write(ctx, zip->output, buf->data, buf->len);
+
+ ++zip->count;
+}
+
+void
+fz_drop_zip_writer(fz_context *ctx, fz_zip_writer *zip)
+{
+ fz_try(ctx)
+ {
+ int offset = fz_tell_output(ctx, zip->output);
+
+ fz_write(ctx, zip->output, zip->central->data, zip->central->len);
+
+ fz_write_int32_le(ctx, zip->output, ZIP_END_OF_CENTRAL_DIRECTORY_SIG);
+ fz_write_int16_le(ctx, zip->output, 0); /* number of this disk */
+ fz_write_int16_le(ctx, zip->output, 0); /* number of disk where central directory starts */
+ fz_write_int16_le(ctx, zip->output, zip->count); /* entries in central directory in this disk */
+ fz_write_int16_le(ctx, zip->output, zip->count); /* entries in central directory in total */
+ fz_write_int32_le(ctx, zip->output, zip->central->len); /* size of the central directory */
+ fz_write_int32_le(ctx, zip->output, offset); /* offset of the central directory */
+ fz_write_int16_le(ctx, zip->output, 5); /* zip file comment length */
+
+ fz_write(ctx, zip->output, "MuPDF", 5);
+ }
+ fz_always(ctx)
+ {
+ fz_drop_output(ctx, zip->output);
+ fz_drop_buffer(ctx, zip->central);
+ fz_free(ctx, zip);
+ }
+ fz_catch(ctx)
+ fz_rethrow(ctx);
+}
+
+fz_zip_writer *
+fz_new_zip_writer(fz_context *ctx, const char *filename)
+{
+ fz_zip_writer *zip = fz_malloc_struct(ctx, fz_zip_writer);
+ fz_try(ctx)
+ {
+ zip->output = fz_new_output_with_path(ctx, filename, 0);
+ zip->central = fz_new_buffer(ctx, 0);
+ }
+ fz_catch(ctx)
+ {
+ fz_drop_output(ctx, zip->output);
+ fz_drop_buffer(ctx, zip->central);
+ fz_free(ctx, zip);
+ fz_rethrow(ctx);
+ }
+ return zip;
+}
diff --git a/source/tools/muconvert.c b/source/tools/muconvert.c
new file mode 100644
index 00000000..5e72b5d3
--- /dev/null
+++ b/source/tools/muconvert.c
@@ -0,0 +1,141 @@
+/*
+ * muconvert -- command line tool for converting documents
+ */
+
+#include "mupdf/fitz.h"
+
+/* input options */
+static const char *password = "";
+static int alphabits = 8;
+static float layout_w = 450;
+static float layout_h = 600;
+static float layout_em = 12;
+static char *layout_css = NULL;
+
+/* output options */
+static const char *output = "out.pdf";
+static const char *format = NULL;
+static const char *options = "";
+
+static fz_context *ctx;
+static fz_document *doc;
+static fz_document_writer *out;
+
+static void usage(void)
+{
+ fprintf(stderr,
+ "mutool convert version " FZ_VERSION "\n"
+ "Usage: mutool convert [options] file [pages]\n"
+ "\t-p -\tpassword\n"
+ "\n"
+ "\t-A -\tnumber of bits of antialiasing (0 to 8)\n"
+ "\t-W -\tpage width for EPUB layout\n"
+ "\t-H -\tpage height for EPUB layout\n"
+ "\t-S -\tfont size for EPUB layout\n"
+ "\t-U -\tfile name of user stylesheet for EPUB layout\n"
+ "\n"
+ "\t-o -\toutput file name (%%d for page number)\n"
+ "\t-F -\toutput format (default inferred from output file name)\n"
+ "\t\tcbz, pdf\n"
+ "\t-O -\toutput format options\n"
+ "\n"
+ "\tpages\tcomma separated list of page numbers and ranges\n"
+ );
+ exit(1);
+}
+
+int muconvert_main(int argc, char **argv)
+{
+ int i, k, n, c;
+
+ while ((c = fz_getopt(argc, argv, "p:A:W:H:S:U:o:F:O:")) != -1)
+ {
+ switch (c)
+ {
+ default: usage(); break;
+
+ case 'p': password = fz_optarg; break;
+ case 'A': alphabits = atoi(fz_optarg); break;
+ case 'W': layout_w = atof(fz_optarg); break;
+ case 'H': layout_h = atof(fz_optarg); break;
+ case 'S': layout_em = atof(fz_optarg); break;
+ case 'U': layout_css = fz_optarg; break;
+
+ case 'o': output = fz_optarg; break;
+ case 'F': format = fz_optarg; break;
+ case 'O': options = fz_optarg; break;
+ }
+ }
+
+ if (fz_optind == argc)
+ usage();
+
+ /* Create a context to hold the exception stack and various caches. */
+ ctx = fz_new_context(NULL, NULL, FZ_STORE_UNLIMITED);
+ if (!ctx)
+ {
+ fprintf(stderr, "cannot create mupdf context\n");
+ return EXIT_FAILURE;
+ }
+
+ /* Register the default file types to handle. */
+ fz_try(ctx)
+ fz_register_document_handlers(ctx);
+ fz_catch(ctx)
+ {
+ fprintf(stderr, "cannot register document handlers: %s\n", fz_caught_message(ctx));
+ fz_drop_context(ctx);
+ return EXIT_FAILURE;
+ }
+
+ fz_set_aa_level(ctx, alphabits);
+
+ if (layout_css)
+ {
+ fz_buffer *buf = fz_read_file(ctx, layout_css);
+ fz_write_buffer_byte(ctx, buf, 0);
+ fz_set_user_css(ctx, (char*)buf->data);
+ fz_drop_buffer(ctx, buf);
+ }
+
+ /* Open the output document. */
+ fz_try(ctx)
+ out = fz_new_document_writer(ctx, output, format, options);
+ fz_catch(ctx)
+ {
+ fprintf(stderr, "cannot open document: %s\n", fz_caught_message(ctx));
+ fz_drop_context(ctx);
+ return EXIT_FAILURE;
+ }
+
+ for (i = fz_optind; i < argc; ++i)
+ {
+ doc = fz_open_document(ctx, argv[i]);
+ if (fz_needs_password(ctx, doc))
+ if (!fz_authenticate_password(ctx, doc, password))
+ fz_throw(ctx, FZ_ERROR_GENERIC, "cannot authenticate password: %s", argv[i]);
+ fz_layout_document(ctx, doc, layout_w, layout_h, layout_em);
+
+ n = fz_count_pages(ctx, doc);
+ for (k = 0; k < n; ++k)
+ {
+ fz_matrix ctm;
+ fz_rect mediabox;
+ fz_page *page;
+ fz_device *dev;
+
+ page = fz_load_page(ctx, doc, k);
+ fz_bound_page(ctx, page, &mediabox);
+ dev = fz_begin_page(ctx, out, &mediabox, &ctm);
+ fz_run_page(ctx, page, dev, &ctm, NULL);
+ fz_end_page(ctx, out, dev);
+ fz_drop_page(ctx, page);
+ }
+
+ fz_drop_document(ctx, doc);
+ }
+
+ fz_drop_document_writer(ctx, out);
+ fz_drop_context(ctx);
+ return EXIT_SUCCESS;
+}
diff --git a/source/tools/mutool.c b/source/tools/mutool.c
index fd38be4d..3ba45ea0 100644
--- a/source/tools/mutool.c
+++ b/source/tools/mutool.c
@@ -8,6 +8,7 @@
#define main main_utf8
#endif
+int muconvert_main(int argc, char *argv[]);
int mudraw_main(int argc, char *argv[]);
int murun_main(int argc, char *argv[]);
int pdfclean_main(int argc, char *argv[]);
@@ -24,6 +25,7 @@ static struct {
char *name;
char *desc;
} tools[] = {
+ { muconvert_main, "convert", "convert document" },
{ mudraw_main, "draw", "convert document" },
{ murun_main, "run", "run javascript" },
{ pdfclean_main, "clean", "rewrite pdf file" },
@@ -66,7 +68,6 @@ int main(int argc, char **argv)
char buf[32];
int i;
-
if (argc == 0)
{
fprintf(stderr, "No command name found!\n");