summaryrefslogtreecommitdiff
path: root/source/fitz
diff options
context:
space:
mode:
authorTor Andersson <tor.andersson@artifex.com>2016-04-12 15:54:22 +0200
committerTor Andersson <tor.andersson@artifex.com>2016-04-26 15:12:57 +0200
commit38d0278ffd22928cfcc66516a5f5a75f2480e702 (patch)
tree1ca80dadfab5ffb41eeb00808c715b53739f4786 /source/fitz
parentebba90e528308e2e5bfdc69b24ed9dd32d42121a (diff)
downloadmupdf-38d0278ffd22928cfcc66516a5f5a75f2480e702.tar.xz
Add 'mutool convert' and new document writer interface.
Only supports CBZ writing for now. Also add a zip file writer.
Diffstat (limited to 'source/fitz')
-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
4 files changed, 258 insertions, 0 deletions
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;
+}