diff options
127 files changed, 8872 insertions, 5438 deletions
@@ -36,6 +36,11 @@ MKDIR_CMD = $(QUIET_MKDIR) mkdir -p $@ # --- Rules --- +FITZ_HDR := fitz/fitz.h fitz/fitz-internal.h +MUPDF_HDR := $(FITZ_HDR) pdf/mupdf.h pdf/mupdf-internal.h +MUXPS_HDR := $(FITZ_HDR) xps/muxps.h xps/muxps-internal.h +MUCBZ_HDR := $(FITZ_HDR) cbz/mucbz.h + $(OUT) $(GEN) : $(MKDIR_CMD) @@ -46,15 +51,15 @@ $(OUT)/%.a : $(OUT)/% : $(OUT)/%.o $(LINK_CMD) -$(OUT)/%.o : fitz/%.c fitz/fitz.h | $(OUT) +$(OUT)/%.o : fitz/%.c $(FITZ_HDR) | $(OUT) $(CC_CMD) -$(OUT)/%.o : draw/%.c fitz/fitz.h | $(OUT) +$(OUT)/%.o : draw/%.c $(FITZ_HDR) | $(OUT) $(CC_CMD) -$(OUT)/%.o : pdf/%.c fitz/fitz.h pdf/mupdf.h | $(OUT) +$(OUT)/%.o : pdf/%.c $(MUPDF_HDR) | $(OUT) $(CC_CMD) -$(OUT)/%.o : xps/%.c fitz/fitz.h xps/muxps.h | $(OUT) +$(OUT)/%.o : xps/%.c $(MUXPS_HDR) | $(OUT) $(CC_CMD) -$(OUT)/%.o : cbz/%.c fitz/fitz.h cbz/mucbz.h | $(OUT) +$(OUT)/%.o : cbz/%.c $(MUCBZ_HDR) | $(OUT) $(CC_CMD) $(OUT)/%.o : apps/%.c fitz/fitz.h pdf/mupdf.h xps/muxps.h cbz/mucbz.h | $(OUT) $(CC_CMD) @@ -157,6 +157,7 @@ OPENJPEG_LIB := $(OUT)/libopenjpeg.a OPENJPEG_SRC := \ bio.c \ cio.c \ + cidx_manager.c \ dwt.c \ event.c \ image.c \ @@ -167,12 +168,16 @@ OPENJPEG_SRC := \ mct.c \ mqc.c \ openjpeg.c \ + phix_manager.c \ pi.c \ + ppix_manager.c \ raw.c \ t1.c \ t2.c \ tcd.c \ tgt.c \ + thix_manager.c \ + tpix_manager.c \ $(OPENJPEG_LIB): $(addprefix $(OUT)/opj_, $(OPENJPEG_SRC:%.c=%.o)) $(OUT)/opj_%.o: $(OPENJPEG_DIR)/%.c | $(OUT) diff --git a/android/jni/Core.mk b/android/jni/Core.mk index 51908298..a4127c67 100644 --- a/android/jni/Core.mk +++ b/android/jni/Core.mk @@ -8,7 +8,7 @@ LOCAL_CFLAGS += -DARCH_ARM -DARCH_THUMB -DARCH_ARM_CAN_LOAD_UNALIGNED LOCAL_C_INCLUDES := \ ../thirdparty/jbig2dec \ - ../thirdparty/openjpeg-1.4/libopenjpeg \ + ../thirdparty/openjpeg-1.5.0/libopenjpeg \ ../thirdparty/jpeg-8d \ ../thirdparty/zlib-1.2.5 \ ../thirdparty/freetype-2.4.8/include \ @@ -28,7 +28,6 @@ LOCAL_SRC_FILES := \ $(MY_ROOT)/fitz/base_getopt.c \ $(MY_ROOT)/fitz/base_hash.c \ $(MY_ROOT)/fitz/base_memory.c \ - $(MY_ROOT)/fitz/base_object.c \ $(MY_ROOT)/fitz/base_string.c \ $(MY_ROOT)/fitz/base_time.c \ $(MY_ROOT)/fitz/crypt_aes.c \ @@ -74,6 +73,7 @@ LOCAL_SRC_FILES := \ $(MY_ROOT)/draw/draw_path.c \ $(MY_ROOT)/draw/draw_simple_scale.c \ $(MY_ROOT)/draw/draw_unpack.c \ + $(MY_ROOT)/pdf/base_object.c \ $(MY_ROOT)/pdf/pdf_annot.c \ $(MY_ROOT)/pdf/pdf_cmap.c \ $(MY_ROOT)/pdf/pdf_cmap_load.c \ @@ -97,6 +97,7 @@ LOCAL_SRC_FILES := \ $(MY_ROOT)/pdf/pdf_repair.c \ $(MY_ROOT)/pdf/pdf_shade.c \ $(MY_ROOT)/pdf/pdf_stream.c \ + $(MY_ROOT)/pdf/pdf_store.c \ $(MY_ROOT)/pdf/pdf_type3.c \ $(MY_ROOT)/pdf/pdf_unicode.c \ $(MY_ROOT)/pdf/pdf_xobject.c \ diff --git a/android/jni/ThirdParty.mk b/android/jni/ThirdParty.mk index dcb7da2a..20e16cee 100644 --- a/android/jni/ThirdParty.mk +++ b/android/jni/ThirdParty.mk @@ -6,7 +6,7 @@ MY_ROOT := ../.. LOCAL_C_INCLUDES := \ ../thirdparty/jbig2dec \ - ../thirdparty/openjpeg-1.4/libopenjpeg \ + ../thirdparty/openjpeg-1.5.0/libopenjpeg \ ../thirdparty/jpeg-8d \ ../thirdparty/zlib-1.2.5 \ ../thirdparty/freetype-2.4.8/include \ @@ -32,24 +32,29 @@ LOCAL_SRC_FILES := \ $(MY_ROOT)/thirdparty/jbig2dec/jbig2_mmr.c \ $(MY_ROOT)/thirdparty/jbig2dec/jbig2_image.c \ $(MY_ROOT)/thirdparty/jbig2dec/jbig2_metadata.c \ - $(MY_ROOT)/thirdparty/openjpeg-1.4/libopenjpeg/bio.c \ - $(MY_ROOT)/thirdparty/openjpeg-1.4/libopenjpeg/cio.c \ - $(MY_ROOT)/thirdparty/openjpeg-1.4/libopenjpeg/dwt.c \ - $(MY_ROOT)/thirdparty/openjpeg-1.4/libopenjpeg/event.c \ - $(MY_ROOT)/thirdparty/openjpeg-1.4/libopenjpeg/image.c \ - $(MY_ROOT)/thirdparty/openjpeg-1.4/libopenjpeg/j2k.c \ - $(MY_ROOT)/thirdparty/openjpeg-1.4/libopenjpeg/j2k_lib.c \ - $(MY_ROOT)/thirdparty/openjpeg-1.4/libopenjpeg/jp2.c \ - $(MY_ROOT)/thirdparty/openjpeg-1.4/libopenjpeg/jpt.c \ - $(MY_ROOT)/thirdparty/openjpeg-1.4/libopenjpeg/mct.c \ - $(MY_ROOT)/thirdparty/openjpeg-1.4/libopenjpeg/mqc.c \ - $(MY_ROOT)/thirdparty/openjpeg-1.4/libopenjpeg/openjpeg.c \ - $(MY_ROOT)/thirdparty/openjpeg-1.4/libopenjpeg/pi.c \ - $(MY_ROOT)/thirdparty/openjpeg-1.4/libopenjpeg/raw.c \ - $(MY_ROOT)/thirdparty/openjpeg-1.4/libopenjpeg/t1.c \ - $(MY_ROOT)/thirdparty/openjpeg-1.4/libopenjpeg/t2.c \ - $(MY_ROOT)/thirdparty/openjpeg-1.4/libopenjpeg/tcd.c \ - $(MY_ROOT)/thirdparty/openjpeg-1.4/libopenjpeg/tgt.c \ + $(MY_ROOT)/thirdparty/openjpeg-1.5.0/libopenjpeg/bio.c \ + $(MY_ROOT)/thirdparty/openjpeg-1.5.0/libopenjpeg/cidx_manager.c \ + $(MY_ROOT)/thirdparty/openjpeg-1.5.0/libopenjpeg/cio.c \ + $(MY_ROOT)/thirdparty/openjpeg-1.5.0/libopenjpeg/dwt.c \ + $(MY_ROOT)/thirdparty/openjpeg-1.5.0/libopenjpeg/event.c \ + $(MY_ROOT)/thirdparty/openjpeg-1.5.0/libopenjpeg/image.c \ + $(MY_ROOT)/thirdparty/openjpeg-1.5.0/libopenjpeg/j2k.c \ + $(MY_ROOT)/thirdparty/openjpeg-1.5.0/libopenjpeg/j2k_lib.c \ + $(MY_ROOT)/thirdparty/openjpeg-1.5.0/libopenjpeg/jp2.c \ + $(MY_ROOT)/thirdparty/openjpeg-1.5.0/libopenjpeg/jpt.c \ + $(MY_ROOT)/thirdparty/openjpeg-1.5.0/libopenjpeg/mct.c \ + $(MY_ROOT)/thirdparty/openjpeg-1.5.0/libopenjpeg/mqc.c \ + $(MY_ROOT)/thirdparty/openjpeg-1.5.0/libopenjpeg/openjpeg.c \ + $(MY_ROOT)/thirdparty/openjpeg-1.5.0/libopenjpeg/phix_manager.c \ + $(MY_ROOT)/thirdparty/openjpeg-1.5.0/libopenjpeg/pi.c \ + $(MY_ROOT)/thirdparty/openjpeg-1.5.0/libopenjpeg/ppix_manager.c \ + $(MY_ROOT)/thirdparty/openjpeg-1.5.0/libopenjpeg/raw.c \ + $(MY_ROOT)/thirdparty/openjpeg-1.5.0/libopenjpeg/t1.c \ + $(MY_ROOT)/thirdparty/openjpeg-1.5.0/libopenjpeg/t2.c \ + $(MY_ROOT)/thirdparty/openjpeg-1.5.0/libopenjpeg/tcd.c \ + $(MY_ROOT)/thirdparty/openjpeg-1.5.0/libopenjpeg/tgt.c \ + $(MY_ROOT)/thirdparty/openjpeg-1.5.0/libopenjpeg/thix_manager.c \ + $(MY_ROOT)/thirdparty/openjpeg-1.5.0/libopenjpeg/tpix_manager.c \ $(MY_ROOT)/thirdparty/jpeg-8d/jaricom.c \ $(MY_ROOT)/thirdparty/jpeg-8d/jcapimin.c \ $(MY_ROOT)/thirdparty/jpeg-8d/jcapistd.c \ diff --git a/android/jni/mupdf.c b/android/jni/mupdf.c index ccd10065..822095ec 100644 --- a/android/jni/mupdf.c +++ b/android/jni/mupdf.c @@ -209,7 +209,7 @@ Java_com_artifex_mupdf_MuPDFCore_drawPage(JNIEnv *env, jobject thiz, jobject bit rect.y0 = patchY; rect.x1 = patchX + patchW; rect.y1 = patchY + patchH; - pix = fz_new_pixmap_with_rect_and_data(ctx, colorspace, rect, pixels); + pix = fz_new_pixmap_with_bbox_and_data(ctx, colorspace, rect, pixels); if (currentPageList == NULL) { fz_clear_pixmap_with_value(ctx, pix, 0xd0); @@ -259,71 +259,83 @@ Java_com_artifex_mupdf_MuPDFCore_drawPage(JNIEnv *env, jobject thiz, jobject bit return 1; } -static int -charat(fz_text_span *span, int idx) +static fz_text_char textcharat(fz_text_page *page, int idx) { + static fz_text_char emptychar = { {0,0,0,0}, ' ' }; + fz_text_block *block; + fz_text_line *line; + fz_text_span *span; int ofs = 0; - while (span) { - if (idx < ofs + span->len) - return span->text[idx - ofs].c; - if (span->eol) { - if (idx == ofs + span->len) - return ' '; - ofs ++; + for (block = page->blocks; block < page->blocks + page->len; block++) + { + for (line = block->lines; line < block->lines + block->len; line++) + { + for (span = line->spans; span < line->spans + line->len; span++) + { + if (idx < ofs + span->len) + return span->text[idx - ofs]; + /* pseudo-newline */ + if (span + 1 == line->spans + line->len) + { + if (idx == ofs + span->len) + return emptychar; + ofs++; + } + ofs += span->len; + } } - ofs += span->len; - span = span->next; } - return 0; + return emptychar; +} + +static int +charat(fz_text_page *page, int idx) +{ + return textcharat(page, idx).c; } static fz_bbox -bboxat(fz_text_span *span, int idx) +bboxcharat(fz_text_page *page, int idx) { - int ofs = 0; - while (span) { - if (idx < ofs + span->len) - return span->text[idx - ofs].bbox; - if (span->eol) { - if (idx == ofs + span->len) - return fz_empty_bbox; - ofs ++; - } - ofs += span->len; - span = span->next; - } - return fz_empty_bbox; + return fz_round_rect(textcharat(page, idx).bbox); } static int -textlen(fz_text_span *span) +textlen(fz_text_page *page) { + fz_text_block *block; + fz_text_line *line; + fz_text_span *span; int len = 0; - while (span) { - len += span->len; - if (span->eol) - len ++; - span = span->next; + for (block = page->blocks; block < page->blocks + page->len; block++) + { + for (line = block->lines; line < block->lines + block->len; line++) + { + for (span = line->spans; span < line->spans + line->len; span++) + len += span->len; + len++; /* pseudo-newline */ + } } return len; } static int -match(fz_text_span *span, const char *s, int n) +match(fz_text_page *page, const char *s, int n) { - int start = n, c; + int orig = n; + int c; while (*s) { - s += chartorune(&c, (char *)s); - if (c == ' ' && charat(span, n) == ' ') { - while (charat(span, n) == ' ') + s += fz_chartorune(&c, (char *)s); + if (c == ' ' && charat(page, n) == ' ') { + while (charat(page, n) == ' ') n++; } else { - if (tolower(c) != tolower(charat(span, n))) + if (tolower(c) != tolower(charat(page, n))) return 0; n++; } } - return n - start; + return n - orig; } static int @@ -433,19 +445,20 @@ Java_com_artifex_mupdf_MuPDFCore_getOutlineInternal(JNIEnv * env, jobject thiz) JNIEXPORT jobjectArray JNICALL Java_com_artifex_mupdf_MuPDFCore_searchPage(JNIEnv * env, jobject thiz, jstring jtext) { - jclass rectClass; - jmethodID ctor; - jobjectArray arr; - jobject rect; - fz_text_span *text = NULL; - fz_device *dev = NULL; - float zoom; - fz_matrix ctm; - int pos; - int len; - int i, n; - int hit_count = 0; - const char *str; + jclass rectClass; + jmethodID ctor; + jobjectArray arr; + jobject rect; + fz_text_sheet *sheet = NULL; + fz_text_page *text = NULL; + fz_device *dev = NULL; + float zoom; + fz_matrix ctm; + int pos; + int len; + int i, n; + int hit_count = 0; + const char *str; rectClass = (*env)->FindClass(env, "android/graphics/RectF"); if (rectClass == NULL) return NULL; @@ -454,18 +467,23 @@ Java_com_artifex_mupdf_MuPDFCore_searchPage(JNIEnv * env, jobject thiz, jstring str = (*env)->GetStringUTFChars(env, jtext, NULL); if (str == NULL) return NULL; + fz_var(sheet); fz_var(text); fz_var(dev); fz_try(ctx) { + fz_rect rect; + if (hit_bbox == NULL) hit_bbox = fz_malloc_array(ctx, MAX_SEARCH_HITS, sizeof(*hit_bbox)); - text = fz_new_text_span(ctx); - dev = fz_new_text_device(ctx, text); zoom = resolution / 72; ctm = fz_scale(zoom, zoom); + rect = fz_transform_rect(ctm, currentMediabox); + sheet = fz_new_text_sheet(ctx); + text = fz_new_text_page(ctx, rect); + dev = fz_new_text_device(ctx, sheet, text); fz_run_page(doc, currentPage, dev, ctm, NULL); fz_free_device(dev); dev = NULL; @@ -476,19 +494,21 @@ Java_com_artifex_mupdf_MuPDFCore_searchPage(JNIEnv * env, jobject thiz, jstring fz_bbox rr = fz_empty_bbox; n = match(text, str, pos); for (i = 0; i < n; i++) - rr = fz_union_bbox(rr, bboxat(text, pos + i)); + rr = fz_union_bbox(rr, bboxcharat(text, pos + i)); if (!fz_is_empty_bbox(rr) && hit_count < MAX_SEARCH_HITS) hit_bbox[hit_count++] = rr; } - fz_free_text_span(ctx, text); - text = NULL; + } + fz_always(ctx) + { + fz_free_text_page(ctx, text); + fz_free_text_sheet(ctx, sheet); + fz_free_device(dev); } fz_catch(ctx) { jclass cls; - fz_free_device(dev); - fz_free_text_span(ctx, text); (*env)->ReleaseStringUTFChars(env, jtext, str); cls = (*env)->FindClass(env, "java/lang/OutOfMemoryError"); if (cls != NULL) diff --git a/android/local.properties b/android/local.properties new file mode 100644 index 00000000..d0e1f0e6 --- /dev/null +++ b/android/local.properties @@ -0,0 +1,2 @@ +#sdk.dir=/Library/android-sdk-mac_x86 +sdk.dir=C:\\Program Files (x86)\\Android\\android-sdk diff --git a/apps/mudraw.c b/apps/mudraw.c index ce59a4e3..29517873 100644 --- a/apps/mudraw.c +++ b/apps/mudraw.c @@ -3,7 +3,6 @@ */ #include "fitz.h" -#include "mupdf.h" #ifdef _MSC_VER #include <winsock2.h> @@ -11,6 +10,8 @@ #include <sys/time.h> #endif +enum { TEXT_PLAIN = 1, TEXT_HTML = 2, TEXT_XML = 3 }; + static char *output = NULL; static float resolution = 72; static float rotation = 0; @@ -25,7 +26,11 @@ static int uselist = 1; static int alphabits = 8; static float gamma_value = 1; static int invert = 0; +static int width = 0; +static int height = 0; +static int fit = 0; +static fz_text_sheet *sheet = NULL; static fz_colorspace *colorspace; static char *filename; @@ -43,6 +48,9 @@ static void usage(void) "\t\tsupported formats: pgm, ppm, pam, png, pbm\n" "\t-p -\tpassword\n" "\t-r -\tresolution in dpi (default: 72)\n" + "\t-w -\twidth (in pixels)\n" + "\t-h -\theight (in pixels)\n" + "\t-f -\tif both -w and -h are used then fit exactly\n" "\t-a\tsave alpha channel (only pam and png)\n" "\t-b -\tnumber of bits of antialiasing (0 to 8)\n" "\t-g\trender in grayscale\n" @@ -152,36 +160,43 @@ static void drawpage(fz_context *ctx, fz_document *doc, int pagenum) if (showtext) { - fz_text_span *text = NULL; + fz_text_page *text = NULL; fz_var(text); fz_try(ctx) { - text = fz_new_text_span(ctx); - dev = fz_new_text_device(ctx, text); + text = fz_new_text_page(ctx, fz_bound_page(doc, page)); + dev = fz_new_text_device(ctx, sheet, text); if (list) fz_run_display_list(list, dev, fz_identity, fz_infinite_bbox, NULL); else fz_run_page(doc, page, dev, fz_identity, NULL); fz_free_device(dev); dev = NULL; - printf("[Page %d]\n", pagenum); - if (showtext > 1) - fz_debug_text_span_xml(text); - else - fz_debug_text_span(text); - printf("\n"); + if (showtext == TEXT_XML) + { + fz_print_text_page_xml(ctx, stdout, text); + } + else if (showtext == TEXT_HTML) + { + fz_print_text_page_html(ctx, stdout, text); + } + else if (showtext == TEXT_PLAIN) + { + fz_print_text_page(ctx, stdout, text); + printf("\f\n"); + } } fz_catch(ctx) { fz_free_device(dev); - fz_free_text_span(ctx, text); + fz_free_text_page(ctx, text); fz_free_display_list(ctx, list); fz_free_page(doc, page); fz_rethrow(ctx); } - fz_free_text_span(ctx, text); + fz_free_text_page(ctx, text); } if (showmd5 || showtime) @@ -191,7 +206,7 @@ static void drawpage(fz_context *ctx, fz_document *doc, int pagenum) { float zoom; fz_matrix ctm; - fz_rect bounds; + fz_rect bounds, bounds2; fz_bbox bbox; fz_pixmap *pix = NULL; @@ -201,13 +216,33 @@ static void drawpage(fz_context *ctx, fz_document *doc, int pagenum) zoom = resolution / 72; ctm = fz_scale(zoom, zoom); ctm = fz_concat(ctm, fz_rotate(rotation)); - bbox = fz_round_rect(fz_transform_rect(ctm, bounds)); + bounds2 = fz_transform_rect(ctm, bounds); + if (width || height) + { + float scalex = width/(bounds2.x1-bounds2.x0); + float scaley = height/(bounds2.y1-bounds2.y0); + + if (width == 0) + scalex = scaley; + if (height == 0) + scaley = scalex; + if (!fit) + { + if (scalex > scaley) + scalex = scaley; + else + scaley = scalex; + } + ctm = fz_concat(ctm, fz_scale(scalex, scaley)); + bounds2 = fz_transform_rect(ctm, bounds); + } + bbox = fz_round_rect(bounds2); /* TODO: banded rendering and multi-page ppm */ fz_try(ctx) { - pix = fz_new_pixmap_with_rect(ctx, colorspace, bbox); + pix = fz_new_pixmap_with_bbox(ctx, colorspace, bbox); if (savealpha) fz_clear_pixmap(ctx, pix); @@ -241,24 +276,18 @@ static void drawpage(fz_context *ctx, fz_document *doc, int pagenum) else if (strstr(output, ".png")) fz_write_png(ctx, pix, buf, savealpha); else if (strstr(output, ".pbm")) { - fz_halftone *ht = fz_get_default_halftone(ctx, 1); - fz_bitmap *bit = fz_halftone_pixmap(ctx, pix, ht); + fz_bitmap *bit = fz_halftone_pixmap(ctx, pix, NULL); fz_write_pbm(ctx, bit, buf); fz_drop_bitmap(ctx, bit); - fz_drop_halftone(ctx, ht); } } if (showmd5) { - fz_md5 md5; unsigned char digest[16]; int i; - fz_md5_init(&md5); - fz_md5_update(&md5, pix->samples, pix->w * pix->h * pix->n); - fz_md5_final(&md5, digest); - + fz_md5_pixmap(pix, digest); printf(" "); for (i = 0; i < 16; i++) printf("%02x", digest[i]); @@ -350,9 +379,9 @@ static void drawoutline(fz_context *ctx, fz_document *doc) { fz_outline *outline = fz_load_outline(doc); if (showoutline > 1) - fz_debug_outline_xml(ctx, outline, 0); + fz_print_outline_xml(ctx, stdout, outline); else - fz_debug_outline(ctx, outline, 0); + fz_print_outline(ctx, stdout, outline); fz_free_outline(ctx, outline); } @@ -370,7 +399,7 @@ int main(int argc, char **argv) fz_var(doc); - while ((c = fz_getopt(argc, argv, "lo:p:r:R:ab:dgmtx5G:I")) != -1) + while ((c = fz_getopt(argc, argv, "lo:p:r:R:ab:dgmtx5G:Iw:h:f")) != -1) { switch (c) { @@ -388,6 +417,9 @@ int main(int argc, char **argv) case 'g': grayscale++; break; case 'd': uselist = 0; break; case 'G': gamma_value = atof(fz_optarg); break; + case 'w': width = atof(fz_optarg); break; + case 'h': height = atof(fz_optarg); break; + case 'f': fit = 1; break; case 'I': invert++; break; default: usage(); break; } @@ -428,9 +460,23 @@ int main(int argc, char **argv) timing.minpage = 0; timing.maxpage = 0; - if (showxml) + if (showxml || showtext == TEXT_XML) printf("<?xml version=\"1.0\"?>\n"); + if (showtext) + sheet = fz_new_text_sheet(ctx); + + if (showtext == TEXT_HTML) + { + printf("<style>\n"); + printf("body{background-color:gray;margin:12tp;}\n"); + printf("div.page{background-color:white;margin:6pt;padding:6pt;}\n"); + printf("div.block{border:1px solid gray;margin:6pt;padding:6pt;}\n"); + printf("p{margin:0;padding:0;}\n"); + printf("</style>\n"); + printf("<body>\n"); + } + fz_try(ctx) { while (fz_optind < argc) @@ -450,7 +496,7 @@ int main(int argc, char **argv) if (!fz_authenticate_password(doc, password)) fz_throw(ctx, "cannot authenticate password: %s", filename); - if (showxml) + if (showxml || showtext == TEXT_XML) printf("<document name=\"%s\">\n", filename); if (showoutline) @@ -464,7 +510,7 @@ int main(int argc, char **argv) drawrange(ctx, doc, argv[fz_optind++]); } - if (showxml) + if (showxml || showtext == TEXT_XML) printf("</document>\n"); fz_close_document(doc); @@ -476,6 +522,14 @@ int main(int argc, char **argv) fz_close_document(doc); } + if (showtext == TEXT_HTML) + { + printf("</body>\n"); + printf("<style>\n"); + fz_print_text_sheet(ctx, stdout, sheet); + printf("</style>\n"); + } + if (showtime) { printf("total %dms / %d pages for an average of %dms\n", diff --git a/apps/mupdfclean.c b/apps/mupdfclean.c index 3130e3f0..caee8d5b 100644 --- a/apps/mupdfclean.c +++ b/apps/mupdfclean.c @@ -10,7 +10,7 @@ */ #include "fitz.h" -#include "mupdf.h" +#include "mupdf-internal.h" static FILE *out = NULL; @@ -53,34 +53,34 @@ static void usage(void) * Garbage collect objects not reachable from the trailer. */ -static void sweepref(fz_obj *ref); +static void sweepref(pdf_obj *ref); -static void sweepobj(fz_obj *obj) +static void sweepobj(pdf_obj *obj) { int i; - if (fz_is_indirect(obj)) + if (pdf_is_indirect(obj)) sweepref(obj); - else if (fz_is_dict(obj)) + else if (pdf_is_dict(obj)) { - int n = fz_dict_len(obj); + int n = pdf_dict_len(obj); for (i = 0; i < n; i++) - sweepobj(fz_dict_get_val(obj, i)); + sweepobj(pdf_dict_get_val(obj, i)); } - else if (fz_is_array(obj)) + else if (pdf_is_array(obj)) { - int n = fz_array_len(obj); + int n = pdf_array_len(obj); for (i = 0; i < n; i++) - sweepobj(fz_array_get(obj, i)); + sweepobj(pdf_array_get(obj, i)); } } -static void sweepref(fz_obj *obj) +static void sweepref(pdf_obj *obj) { - int num = fz_to_num(obj); - int gen = fz_to_gen(obj); + int num = pdf_to_num(obj); + int gen = pdf_to_gen(obj); if (num < 0 || num >= xref->len) return; @@ -94,12 +94,12 @@ static void sweepref(fz_obj *obj) { if (pdf_is_stream(xref, num, gen)) { - fz_obj *len = fz_dict_gets(obj, "Length"); - if (fz_is_indirect(len)) + pdf_obj *len = pdf_dict_gets(obj, "Length"); + if (pdf_is_indirect(len)) { - uselist[fz_to_num(len)] = 0; - len = fz_resolve_indirect(len); - fz_dict_puts(obj, "Length", len); + uselist[pdf_to_num(len)] = 0; + len = pdf_resolve_indirect(len); + pdf_dict_puts(obj, "Length", len); } } } @@ -108,7 +108,7 @@ static void sweepref(fz_obj *obj) /* Leave broken */ } - sweepobj(fz_resolve_indirect(obj)); + sweepobj(pdf_resolve_indirect(obj)); } /* @@ -124,7 +124,7 @@ static void removeduplicateobjs(void) /* Only compare an object to objects preceding it */ for (other = 1; other < num; other++) { - fz_obj *a, *b; + pdf_obj *a, *b; if (num == other || !uselist[num] || !uselist[other]) continue; @@ -148,10 +148,10 @@ static void removeduplicateobjs(void) a = xref->table[num].obj; b = xref->table[other].obj; - a = fz_resolve_indirect(a); - b = fz_resolve_indirect(b); + a = pdf_resolve_indirect(a); + b = pdf_resolve_indirect(b); - if (fz_objcmp(a, b)) + if (pdf_objcmp(a, b)) continue; /* Keep the lowest numbered object */ @@ -195,23 +195,23 @@ static void compactxref(void) * removing duplicate objects and compacting the xref. */ -static void renumberobj(fz_obj *obj) +static void renumberobj(pdf_obj *obj) { int i; fz_context *ctx = xref->ctx; - if (fz_is_dict(obj)) + if (pdf_is_dict(obj)) { - int n = fz_dict_len(obj); + int n = pdf_dict_len(obj); for (i = 0; i < n; i++) { - fz_obj *key = fz_dict_get_key(obj, i); - fz_obj *val = fz_dict_get_val(obj, i); - if (fz_is_indirect(val)) + pdf_obj *key = pdf_dict_get_key(obj, i); + pdf_obj *val = pdf_dict_get_val(obj, i); + if (pdf_is_indirect(val)) { - val = fz_new_indirect(ctx, renumbermap[fz_to_num(val)], 0, xref); + val = pdf_new_indirect(ctx, renumbermap[pdf_to_num(val)], 0, xref); fz_dict_put(obj, key, val); - fz_drop_obj(val); + pdf_drop_obj(val); } else { @@ -220,17 +220,17 @@ static void renumberobj(fz_obj *obj) } } - else if (fz_is_array(obj)) + else if (pdf_is_array(obj)) { - int n = fz_array_len(obj); + int n = pdf_array_len(obj); for (i = 0; i < n; i++) { - fz_obj *val = fz_array_get(obj, i); - if (fz_is_indirect(val)) + pdf_obj *val = pdf_array_get(obj, i); + if (pdf_is_indirect(val)) { - val = fz_new_indirect(ctx, renumbermap[fz_to_num(val)], 0, xref); - fz_array_put(obj, i, val); - fz_drop_obj(val); + val = pdf_new_indirect(ctx, renumbermap[pdf_to_num(val)], 0, xref); + pdf_array_put(obj, i, val); + pdf_drop_obj(val); } else { @@ -250,13 +250,13 @@ static void renumberobjs(void) renumberobj(xref->trailer); for (num = 0; num < xref->len; num++) { - fz_obj *obj = xref->table[num].obj; + pdf_obj *obj = xref->table[num].obj; - if (fz_is_indirect(obj)) + if (pdf_is_indirect(obj)) { - obj = fz_new_indirect(ctx, renumbermap[fz_to_num(obj)], 0, xref); + obj = pdf_new_indirect(ctx, renumbermap[pdf_to_num(obj)], 0, xref); pdf_update_object(xref, num, 0, obj); - fz_drop_obj(obj); + pdf_drop_obj(obj); } else { @@ -282,7 +282,7 @@ static void renumberobjs(void) else { if (oldxref[num].obj) - fz_drop_obj(oldxref[num].obj); + pdf_drop_obj(oldxref[num].obj); } } @@ -302,25 +302,25 @@ static void renumberobjs(void) static void retainpages(int argc, char **argv) { - fz_obj *oldroot, *root, *pages, *kids, *countobj, *parent, *olddests; + pdf_obj *oldroot, *root, *pages, *kids, *countobj, *parent, *olddests; /* Keep only pages/type and (reduced) dest entries to avoid * references to unretained pages */ - oldroot = fz_dict_gets(xref->trailer, "Root"); - pages = fz_dict_gets(oldroot, "Pages"); + oldroot = pdf_dict_gets(xref->trailer, "Root"); + pages = pdf_dict_gets(oldroot, "Pages"); olddests = pdf_load_name_tree(xref, "Dests"); - root = fz_new_dict(ctx, 2); - fz_dict_puts(root, "Type", fz_dict_gets(oldroot, "Type")); - fz_dict_puts(root, "Pages", fz_dict_gets(oldroot, "Pages")); + root = pdf_new_dict(ctx, 2); + pdf_dict_puts(root, "Type", pdf_dict_gets(oldroot, "Type")); + pdf_dict_puts(root, "Pages", pdf_dict_gets(oldroot, "Pages")); - pdf_update_object(xref, fz_to_num(oldroot), fz_to_gen(oldroot), root); + pdf_update_object(xref, pdf_to_num(oldroot), pdf_to_gen(oldroot), root); - fz_drop_obj(root); + pdf_drop_obj(root); /* Create a new kids array with only the pages we want to keep */ - parent = fz_new_indirect(ctx, fz_to_num(pages), fz_to_gen(pages), xref); - kids = fz_new_array(ctx, 1); + parent = pdf_new_indirect(ctx, pdf_to_num(pages), pdf_to_gen(pages), xref); + kids = pdf_new_array(ctx, 1); /* Retain pages specified */ while (argc - fz_optind) @@ -357,13 +357,13 @@ static void retainpages(int argc, char **argv) for (page = spage; page <= epage; page++) { - fz_obj *pageobj = xref->page_objs[page-1]; - fz_obj *pageref = xref->page_refs[page-1]; + pdf_obj *pageobj = xref->page_objs[page-1]; + pdf_obj *pageref = xref->page_refs[page-1]; - fz_dict_puts(pageobj, "Parent", parent); + pdf_dict_puts(pageobj, "Parent", parent); /* Store page object in new kids array */ - fz_array_push(kids, pageref); + pdf_array_push(kids, pageref); } spec = fz_strsep(&pagelist, ","); @@ -372,48 +372,48 @@ static void retainpages(int argc, char **argv) fz_optind++; } - fz_drop_obj(parent); + pdf_drop_obj(parent); /* Update page count and kids array */ - countobj = fz_new_int(ctx, fz_array_len(kids)); - fz_dict_puts(pages, "Count", countobj); - fz_drop_obj(countobj); - fz_dict_puts(pages, "Kids", kids); - fz_drop_obj(kids); + countobj = pdf_new_int(ctx, pdf_array_len(kids)); + pdf_dict_puts(pages, "Count", countobj); + pdf_drop_obj(countobj); + pdf_dict_puts(pages, "Kids", kids); + pdf_drop_obj(kids); /* Also preserve the (partial) Dests name tree */ if (olddests) { int i; - fz_obj *names = fz_new_dict(ctx, 1); - fz_obj *dests = fz_new_dict(ctx, 1); - fz_obj *names_list = fz_new_array(ctx, 32); + pdf_obj *names = pdf_new_dict(ctx, 1); + pdf_obj *dests = pdf_new_dict(ctx, 1); + pdf_obj *names_list = pdf_new_array(ctx, 32); - for (i = 0; i < fz_dict_len(olddests); i++) + for (i = 0; i < pdf_dict_len(olddests); i++) { - fz_obj *key = fz_dict_get_key(olddests, i); - fz_obj *val = fz_dict_get_val(olddests, i); - fz_obj *key_str = fz_new_string(ctx, fz_to_name(key), strlen(fz_to_name(key))); - fz_obj *dest = fz_dict_gets(val, "D"); + pdf_obj *key = pdf_dict_get_key(olddests, i); + pdf_obj *val = pdf_dict_get_val(olddests, i); + pdf_obj *key_str = pdf_new_string(ctx, pdf_to_name(key), strlen(pdf_to_name(key))); + pdf_obj *dest = pdf_dict_gets(val, "D"); - dest = fz_array_get(dest ? dest : val, 0); - if (fz_array_contains(fz_dict_gets(pages, "Kids"), dest)) + dest = pdf_array_get(dest ? dest : val, 0); + if (pdf_array_contains(pdf_dict_gets(pages, "Kids"), dest)) { - fz_array_push(names_list, key_str); - fz_array_push(names_list, val); + pdf_array_push(names_list, key_str); + pdf_array_push(names_list, val); } - fz_drop_obj(key_str); + pdf_drop_obj(key_str); } - root = fz_dict_gets(xref->trailer, "Root"); - fz_dict_puts(dests, "Names", names_list); - fz_dict_puts(names, "Dests", dests); - fz_dict_puts(root, "Names", names); + root = pdf_dict_gets(xref->trailer, "Root"); + pdf_dict_puts(dests, "Names", names_list); + pdf_dict_puts(names, "Dests", dests); + pdf_dict_puts(root, "Names", names); - fz_drop_obj(names); - fz_drop_obj(dests); - fz_drop_obj(names_list); - fz_drop_obj(olddests); + pdf_drop_obj(names); + pdf_drop_obj(dests); + pdf_drop_obj(names_list); + pdf_drop_obj(olddests); } } @@ -423,7 +423,7 @@ static void retainpages(int argc, char **argv) static void preloadobjstms(void) { - fz_obj *obj; + pdf_obj *obj; int num; for (num = 0; num < xref->len; num++) @@ -431,7 +431,7 @@ static void preloadobjstms(void) if (xref->table[num].type == 'o') { obj = pdf_load_object(xref, num, 0); - fz_drop_obj(obj); + pdf_drop_obj(obj); } } } @@ -482,57 +482,57 @@ static fz_buffer *hexbuf(unsigned char *p, int n) return buf; } -static void addhexfilter(fz_obj *dict) +static void addhexfilter(pdf_obj *dict) { - fz_obj *f, *dp, *newf, *newdp; - fz_obj *ahx, *nullobj; + pdf_obj *f, *dp, *newf, *newdp; + pdf_obj *ahx, *nullobj; ahx = fz_new_name(ctx, "ASCIIHexDecode"); - nullobj = fz_new_null(ctx); + nullobj = pdf_new_null(ctx); newf = newdp = NULL; - f = fz_dict_gets(dict, "Filter"); - dp = fz_dict_gets(dict, "DecodeParms"); + f = pdf_dict_gets(dict, "Filter"); + dp = pdf_dict_gets(dict, "DecodeParms"); - if (fz_is_name(f)) + if (pdf_is_name(f)) { - newf = fz_new_array(ctx, 2); - fz_array_push(newf, ahx); - fz_array_push(newf, f); + newf = pdf_new_array(ctx, 2); + pdf_array_push(newf, ahx); + pdf_array_push(newf, f); f = newf; - if (fz_is_dict(dp)) + if (pdf_is_dict(dp)) { - newdp = fz_new_array(ctx, 2); - fz_array_push(newdp, nullobj); - fz_array_push(newdp, dp); + newdp = pdf_new_array(ctx, 2); + pdf_array_push(newdp, nullobj); + pdf_array_push(newdp, dp); dp = newdp; } } - else if (fz_is_array(f)) + else if (pdf_is_array(f)) { - fz_array_insert(f, ahx); - if (fz_is_array(dp)) - fz_array_insert(dp, nullobj); + pdf_array_insert(f, ahx); + if (pdf_is_array(dp)) + pdf_array_insert(dp, nullobj); } else f = ahx; - fz_dict_puts(dict, "Filter", f); + pdf_dict_puts(dict, "Filter", f); if (dp) - fz_dict_puts(dict, "DecodeParms", dp); + pdf_dict_puts(dict, "DecodeParms", dp); - fz_drop_obj(ahx); - fz_drop_obj(nullobj); + pdf_drop_obj(ahx); + pdf_drop_obj(nullobj); if (newf) - fz_drop_obj(newf); + pdf_drop_obj(newf); if (newdp) - fz_drop_obj(newdp); + pdf_drop_obj(newdp); } -static void copystream(fz_obj *obj, int num, int gen) +static void copystream(pdf_obj *obj, int num, int gen) { fz_buffer *buf, *tmp; - fz_obj *newlen; + pdf_obj *newlen; buf = pdf_load_raw_stream(xref, num, gen); @@ -544,13 +544,13 @@ static void copystream(fz_obj *obj, int num, int gen) addhexfilter(obj); - newlen = fz_new_int(ctx, buf->len); - fz_dict_puts(obj, "Length", newlen); - fz_drop_obj(newlen); + newlen = pdf_new_int(ctx, buf->len); + pdf_dict_puts(obj, "Length", newlen); + pdf_drop_obj(newlen); } fprintf(out, "%d %d obj\n", num, gen); - fz_fprint_obj(out, obj, doexpand == 0); + pdf_fprint_obj(out, obj, doexpand == 0); fprintf(out, "stream\n"); fwrite(buf->data, 1, buf->len, out); fprintf(out, "endstream\nendobj\n\n"); @@ -558,15 +558,15 @@ static void copystream(fz_obj *obj, int num, int gen) fz_drop_buffer(ctx, buf); } -static void expandstream(fz_obj *obj, int num, int gen) +static void expandstream(pdf_obj *obj, int num, int gen) { fz_buffer *buf, *tmp; - fz_obj *newlen; + pdf_obj *newlen; buf = pdf_load_stream(xref, num, gen); - fz_dict_dels(obj, "Filter"); - fz_dict_dels(obj, "DecodeParms"); + pdf_dict_dels(obj, "Filter"); + pdf_dict_dels(obj, "DecodeParms"); if (doascii && isbinarystream(buf)) { @@ -577,12 +577,12 @@ static void expandstream(fz_obj *obj, int num, int gen) addhexfilter(obj); } - newlen = fz_new_int(ctx, buf->len); - fz_dict_puts(obj, "Length", newlen); - fz_drop_obj(newlen); + newlen = pdf_new_int(ctx, buf->len); + pdf_dict_puts(obj, "Length", newlen); + pdf_drop_obj(newlen); fprintf(out, "%d %d obj\n", num, gen); - fz_fprint_obj(out, obj, doexpand == 0); + pdf_fprint_obj(out, obj, doexpand == 0); fprintf(out, "stream\n"); fwrite(buf->data, 1, buf->len, out); fprintf(out, "endstream\nendobj\n\n"); @@ -592,25 +592,25 @@ static void expandstream(fz_obj *obj, int num, int gen) static void writeobject(int num, int gen) { - fz_obj *obj; - fz_obj *type; + pdf_obj *obj; + pdf_obj *type; obj = pdf_load_object(xref, num, gen); /* skip ObjStm and XRef objects */ - if (fz_is_dict(obj)) + if (pdf_is_dict(obj)) { - type = fz_dict_gets(obj, "Type"); - if (fz_is_name(type) && !strcmp(fz_to_name(type), "ObjStm")) + type = pdf_dict_gets(obj, "Type"); + if (pdf_is_name(type) && !strcmp(pdf_to_name(type), "ObjStm")) { uselist[num] = 0; - fz_drop_obj(obj); + pdf_drop_obj(obj); return; } - if (fz_is_name(type) && !strcmp(fz_to_name(type), "XRef")) + if (pdf_is_name(type) && !strcmp(pdf_to_name(type), "XRef")) { uselist[num] = 0; - fz_drop_obj(obj); + pdf_drop_obj(obj); return; } } @@ -618,7 +618,7 @@ static void writeobject(int num, int gen) if (!pdf_is_stream(xref, num, gen)) { fprintf(out, "%d %d obj\n", num, gen); - fz_fprint_obj(out, obj, doexpand == 0); + pdf_fprint_obj(out, obj, doexpand == 0); fprintf(out, "endobj\n\n"); } else @@ -626,24 +626,24 @@ static void writeobject(int num, int gen) int dontexpand = 0; if (doexpand != 0 && doexpand != expand_all) { - fz_obj *o; + pdf_obj *o; - if ((o = fz_dict_gets(obj, "Type"), !strcmp(fz_to_name(o), "XObject")) && - (o = fz_dict_gets(obj, "Subtype"), !strcmp(fz_to_name(o), "Image"))) + if ((o = pdf_dict_gets(obj, "Type"), !strcmp(pdf_to_name(o), "XObject")) && + (o = pdf_dict_gets(obj, "Subtype"), !strcmp(pdf_to_name(o), "Image"))) dontexpand = !(doexpand & expand_images); - if (o = fz_dict_gets(obj, "Type"), !strcmp(fz_to_name(o), "Font")) + if (o = pdf_dict_gets(obj, "Type"), !strcmp(pdf_to_name(o), "Font")) dontexpand = !(doexpand & expand_fonts); - if (o = fz_dict_gets(obj, "Type"), !strcmp(fz_to_name(o), "FontDescriptor")) + if (o = pdf_dict_gets(obj, "Type"), !strcmp(pdf_to_name(o), "FontDescriptor")) dontexpand = !(doexpand & expand_fonts); - if ((o = fz_dict_gets(obj, "Length1")) != NULL) + if ((o = pdf_dict_gets(obj, "Length1")) != NULL) dontexpand = !(doexpand & expand_fonts); - if ((o = fz_dict_gets(obj, "Length2")) != NULL) + if ((o = pdf_dict_gets(obj, "Length2")) != NULL) dontexpand = !(doexpand & expand_fonts); - if ((o = fz_dict_gets(obj, "Length3")) != NULL) + if ((o = pdf_dict_gets(obj, "Length3")) != NULL) dontexpand = !(doexpand & expand_fonts); - if (o = fz_dict_gets(obj, "Subtype"), !strcmp(fz_to_name(o), "Type1C")) + if (o = pdf_dict_gets(obj, "Subtype"), !strcmp(pdf_to_name(o), "Type1C")) dontexpand = !(doexpand & expand_fonts); - if (o = fz_dict_gets(obj, "Subtype"), !strcmp(fz_to_name(o), "CIDFontType0C")) + if (o = pdf_dict_gets(obj, "Subtype"), !strcmp(pdf_to_name(o), "CIDFontType0C")) dontexpand = !(doexpand & expand_fonts); } if (doexpand && !dontexpand && !pdf_is_jpx_image(ctx, obj)) @@ -652,13 +652,13 @@ static void writeobject(int num, int gen) copystream(obj, num, gen); } - fz_drop_obj(obj); + pdf_drop_obj(obj); } static void writexref(void) { - fz_obj *trailer; - fz_obj *obj; + pdf_obj *trailer; + pdf_obj *obj; int startxref; int num; @@ -674,29 +674,29 @@ static void writexref(void) } fprintf(out, "\n"); - trailer = fz_new_dict(ctx, 5); + trailer = pdf_new_dict(ctx, 5); - obj = fz_new_int(ctx, xref->len); - fz_dict_puts(trailer, "Size", obj); - fz_drop_obj(obj); + obj = pdf_new_int(ctx, xref->len); + pdf_dict_puts(trailer, "Size", obj); + pdf_drop_obj(obj); - obj = fz_dict_gets(xref->trailer, "Info"); + obj = pdf_dict_gets(xref->trailer, "Info"); if (obj) - fz_dict_puts(trailer, "Info", obj); + pdf_dict_puts(trailer, "Info", obj); - obj = fz_dict_gets(xref->trailer, "Root"); + obj = pdf_dict_gets(xref->trailer, "Root"); if (obj) - fz_dict_puts(trailer, "Root", obj); + pdf_dict_puts(trailer, "Root", obj); - obj = fz_dict_gets(xref->trailer, "ID"); + obj = pdf_dict_gets(xref->trailer, "ID"); if (obj) - fz_dict_puts(trailer, "ID", obj); + pdf_dict_puts(trailer, "ID", obj); fprintf(out, "trailer\n"); - fz_fprint_obj(out, trailer, doexpand == 0); + pdf_fprint_obj(out, trailer, doexpand == 0); fprintf(out, "\n"); - fz_drop_obj(trailer); + pdf_drop_obj(trailer); fprintf(out, "startxref\n%d\n%%%%EOF\n", startxref); } @@ -792,7 +792,7 @@ int main(int argc, char **argv) xref = pdf_open_document(ctx, infile); if (pdf_needs_password(xref)) if (!pdf_authenticate_password(xref, password)) - fz_throw(ctx, "cannot authenticate password: %s\n", infile); + fz_throw(ctx, "cannot authenticate password: %s", infile); out = fopen(outfile, "wb"); if (!out) diff --git a/apps/mupdfextract.c b/apps/mupdfextract.c index f309f39a..a6a677cd 100644 --- a/apps/mupdfextract.c +++ b/apps/mupdfextract.c @@ -2,7 +2,6 @@ * pdfextract -- the ultimate way to extract images and fonts from pdfs */ -#include "fitz.h" #include "mupdf.h" static pdf_document *doc = NULL; @@ -17,96 +16,81 @@ static void usage(void) exit(1); } -static int isimage(fz_obj *obj) +static int isimage(pdf_obj *obj) { - fz_obj *type = fz_dict_gets(obj, "Subtype"); - return fz_is_name(type) && !strcmp(fz_to_name(type), "Image"); + pdf_obj *type = pdf_dict_gets(obj, "Subtype"); + return pdf_is_name(type) && !strcmp(pdf_to_name(type), "Image"); } -static int isfontdesc(fz_obj *obj) +static int isfontdesc(pdf_obj *obj) { - fz_obj *type = fz_dict_gets(obj, "Type"); - return fz_is_name(type) && !strcmp(fz_to_name(type), "FontDescriptor"); + pdf_obj *type = pdf_dict_gets(obj, "Type"); + return pdf_is_name(type) && !strcmp(pdf_to_name(type), "FontDescriptor"); } static void saveimage(int num) { + fz_image *image; fz_pixmap *img; - fz_obj *ref; - char name[1024]; + pdf_obj *ref; + char name[32]; - ref = fz_new_indirect(ctx, num, 0, doc); + ref = pdf_new_indirect(ctx, num, 0, doc); /* TODO: detect DCTD and save as jpeg */ - img = pdf_load_image(doc, ref); + image = pdf_load_image(doc, ref); + img = fz_image_to_pixmap(ctx, image, 0, 0); + fz_drop_image(ctx, image); - if (dorgb && img->colorspace && img->colorspace != fz_device_rgb) - { - fz_pixmap *temp; - temp = fz_new_pixmap_with_rect(ctx, fz_device_rgb, fz_bound_pixmap(img)); - fz_convert_pixmap(ctx, img, temp); - fz_drop_pixmap(ctx, img); - img = temp; - } - - if (img->n <= 4) - { - sprintf(name, "img-%04d.png", num); - printf("extracting image %s\n", name); - fz_write_png(ctx, img, name, 0); - } - else - { - sprintf(name, "img-%04d.pam", num); - printf("extracting image %s\n", name); - fz_write_pam(ctx, img, name, 0); - } + sprintf(name, "img-%04d", num); + fz_write_pixmap(ctx, img, name, dorgb); fz_drop_pixmap(ctx, img); - fz_drop_obj(ref); + pdf_drop_obj(ref); } -static void savefont(fz_obj *dict, int num) +static void savefont(pdf_obj *dict, int num) { char name[1024]; char *subtype; fz_buffer *buf; - fz_obj *stream = NULL; - fz_obj *obj; + pdf_obj *stream = NULL; + pdf_obj *obj; char *ext = ""; FILE *f; char *fontname = "font"; - int n; + int n, len; + unsigned char *data; - obj = fz_dict_gets(dict, "FontName"); + obj = pdf_dict_gets(dict, "FontName"); if (obj) - fontname = fz_to_name(obj); + fontname = pdf_to_name(obj); - obj = fz_dict_gets(dict, "FontFile"); + obj = pdf_dict_gets(dict, "FontFile"); if (obj) { stream = obj; ext = "pfa"; } - obj = fz_dict_gets(dict, "FontFile2"); + obj = pdf_dict_gets(dict, "FontFile2"); if (obj) { stream = obj; ext = "ttf"; } - obj = fz_dict_gets(dict, "FontFile3"); + obj = pdf_dict_gets(dict, "FontFile3"); if (obj) { stream = obj; - obj = fz_dict_gets(obj, "Subtype"); - if (obj && !fz_is_name(obj)) + obj = pdf_dict_gets(obj, "Subtype"); + if (obj && !pdf_is_name(obj)) fz_throw(ctx, "Invalid font descriptor subtype"); - subtype = fz_to_name(obj); + subtype = pdf_to_name(obj); if (!strcmp(subtype, "Type1C")) ext = "cff"; else if (!strcmp(subtype, "CIDFontType0C")) @@ -121,7 +105,7 @@ static void savefont(fz_obj *dict, int num) return; } - buf = pdf_load_stream(doc, fz_to_num(stream), fz_to_gen(stream)); + buf = pdf_load_stream(doc, pdf_to_num(stream), pdf_to_gen(stream)); sprintf(name, "%s-%04d.%s", fontname, num, ext); printf("extracting font %s\n", name); @@ -130,8 +114,9 @@ static void savefont(fz_obj *dict, int num) if (!f) fz_throw(ctx, "Error creating font file"); - n = fwrite(buf->data, 1, buf->len, f); - if (n < buf->len) + len = fz_buffer_storage(ctx, buf, &data); + n = fwrite(data, 1, len, f); + if (n < len) fz_throw(ctx, "Error writing font file"); if (fclose(f) < 0) @@ -142,7 +127,7 @@ static void savefont(fz_obj *dict, int num) static void showobject(int num) { - fz_obj *obj; + pdf_obj *obj; if (!doc) fz_throw(ctx, "no file specified"); @@ -154,7 +139,7 @@ static void showobject(int num) else if (isfontdesc(obj)) savefont(obj, num); - fz_drop_obj(obj); + pdf_drop_obj(obj); } #ifdef MUPDF_COMBINED_EXE @@ -192,11 +177,11 @@ int main(int argc, char **argv) doc = pdf_open_document(ctx, infile); if (pdf_needs_password(doc)) if (!pdf_authenticate_password(doc, password)) - fz_throw(ctx, "cannot authenticate password: %s\n", infile); + fz_throw(ctx, "cannot authenticate password: %s", infile); if (fz_optind == argc) { - for (o = 0; o < doc->len; o++) + for (o = 0; o < pdf_count_objects(doc); o++) showobject(o); } else diff --git a/apps/mupdfinfo.c b/apps/mupdfinfo.c index 3c98c772..e02d8d1a 100644 --- a/apps/mupdfinfo.c +++ b/apps/mupdfinfo.c @@ -4,7 +4,7 @@ */ #include "fitz.h" -#include "mupdf.h" +#include "mupdf-internal.h" pdf_document *xref; fz_context *ctx; @@ -28,48 +28,48 @@ enum struct info { int page; - fz_obj *pageref; - fz_obj *pageobj; + pdf_obj *pageref; + pdf_obj *pageobj; union { struct { - fz_obj *obj; + pdf_obj *obj; } info; struct { - fz_obj *obj; + pdf_obj *obj; } crypt; struct { - fz_obj *obj; + pdf_obj *obj; fz_rect *bbox; } dim; struct { - fz_obj *obj; - fz_obj *subtype; - fz_obj *name; + pdf_obj *obj; + pdf_obj *subtype; + pdf_obj *name; } font; struct { - fz_obj *obj; - fz_obj *width; - fz_obj *height; - fz_obj *bpc; - fz_obj *filter; - fz_obj *cs; - fz_obj *altcs; + pdf_obj *obj; + pdf_obj *width; + pdf_obj *height; + pdf_obj *bpc; + pdf_obj *filter; + pdf_obj *cs; + pdf_obj *altcs; } image; struct { - fz_obj *obj; - fz_obj *type; + pdf_obj *obj; + pdf_obj *type; } shading; struct { - fz_obj *obj; - fz_obj *type; - fz_obj *paint; - fz_obj *tiling; - fz_obj *shading; + pdf_obj *obj; + pdf_obj *type; + pdf_obj *paint; + pdf_obj *tiling; + pdf_obj *shading; } pattern; struct { - fz_obj *obj; - fz_obj *groupsubtype; - fz_obj *reference; + pdf_obj *obj; + pdf_obj *groupsubtype; + pdf_obj *reference; } form; } u; }; @@ -168,36 +168,36 @@ infousage(void) static void showglobalinfo(void) { - fz_obj *obj; + pdf_obj *obj; printf("\nPDF-%d.%d\n", xref->version / 10, xref->version % 10); - obj = fz_dict_gets(xref->trailer, "Info"); + obj = pdf_dict_gets(xref->trailer, "Info"); if (obj) { - printf("Info object (%d %d R):\n", fz_to_num(obj), fz_to_gen(obj)); - fz_debug_obj(fz_resolve_indirect(obj)); + printf("Info object (%d %d R):\n", pdf_to_num(obj), pdf_to_gen(obj)); + pdf_print_obj(pdf_resolve_indirect(obj)); } - obj = fz_dict_gets(xref->trailer, "Encrypt"); + obj = pdf_dict_gets(xref->trailer, "Encrypt"); if (obj) { - printf("\nEncryption object (%d %d R):\n", fz_to_num(obj), fz_to_gen(obj)); - fz_debug_obj(fz_resolve_indirect(obj)); + printf("\nEncryption object (%d %d R):\n", pdf_to_num(obj), pdf_to_gen(obj)); + pdf_print_obj(pdf_resolve_indirect(obj)); } printf("\nPages: %d\n\n", pagecount); } static void -gatherdimensions(int page, fz_obj *pageref, fz_obj *pageobj) +gatherdimensions(int page, pdf_obj *pageref, pdf_obj *pageobj) { fz_rect bbox; - fz_obj *obj; + pdf_obj *obj; int j; - obj = fz_dict_gets(pageobj, "MediaBox"); - if (!fz_is_array(obj)) + obj = pdf_dict_gets(pageobj, "MediaBox"); + if (!pdf_is_array(obj)) return; bbox = pdf_to_rect(ctx, obj); @@ -222,33 +222,33 @@ gatherdimensions(int page, fz_obj *pageref, fz_obj *pageobj) } static void -gatherfonts(int page, fz_obj *pageref, fz_obj *pageobj, fz_obj *dict) +gatherfonts(int page, pdf_obj *pageref, pdf_obj *pageobj, pdf_obj *dict) { int i, n; - n = fz_dict_len(dict); + n = pdf_dict_len(dict); for (i = 0; i < n; i++) { - fz_obj *fontdict = NULL; - fz_obj *subtype = NULL; - fz_obj *basefont = NULL; - fz_obj *name = NULL; + pdf_obj *fontdict = NULL; + pdf_obj *subtype = NULL; + pdf_obj *basefont = NULL; + pdf_obj *name = NULL; int k; - fontdict = fz_dict_get_val(dict, i); - if (!fz_is_dict(fontdict)) + fontdict = pdf_dict_get_val(dict, i); + if (!pdf_is_dict(fontdict)) { - fz_warn(ctx, "not a font dict (%d %d R)", fz_to_num(fontdict), fz_to_gen(fontdict)); + fz_warn(ctx, "not a font dict (%d %d R)", pdf_to_num(fontdict), pdf_to_gen(fontdict)); continue; } - subtype = fz_dict_gets(fontdict, "Subtype"); - basefont = fz_dict_gets(fontdict, "BaseFont"); - if (!basefont || fz_is_null(basefont)) - name = fz_dict_gets(fontdict, "Name"); + subtype = pdf_dict_gets(fontdict, "Subtype"); + basefont = pdf_dict_gets(fontdict, "BaseFont"); + if (!basefont || pdf_is_null(basefont)) + name = pdf_dict_gets(fontdict, "Name"); for (k = 0; k < fonts; k++) - if (!fz_objcmp(font[k].u.font.obj, fontdict)) + if (!pdf_objcmp(font[k].u.font.obj, fontdict)) break; if (k < fonts) @@ -267,57 +267,57 @@ gatherfonts(int page, fz_obj *pageref, fz_obj *pageobj, fz_obj *dict) } static void -gatherimages(int page, fz_obj *pageref, fz_obj *pageobj, fz_obj *dict) +gatherimages(int page, pdf_obj *pageref, pdf_obj *pageobj, pdf_obj *dict) { int i, n; - n = fz_dict_len(dict); + n = pdf_dict_len(dict); for (i = 0; i < n; i++) { - fz_obj *imagedict; - fz_obj *type; - fz_obj *width; - fz_obj *height; - fz_obj *bpc = NULL; - fz_obj *filter = NULL; - fz_obj *cs = NULL; - fz_obj *altcs; + pdf_obj *imagedict; + pdf_obj *type; + pdf_obj *width; + pdf_obj *height; + pdf_obj *bpc = NULL; + pdf_obj *filter = NULL; + pdf_obj *cs = NULL; + pdf_obj *altcs; int k; - imagedict = fz_dict_get_val(dict, i); - if (!fz_is_dict(imagedict)) + imagedict = pdf_dict_get_val(dict, i); + if (!pdf_is_dict(imagedict)) { - fz_warn(ctx, "not an image dict (%d %d R)", fz_to_num(imagedict), fz_to_gen(imagedict)); + fz_warn(ctx, "not an image dict (%d %d R)", pdf_to_num(imagedict), pdf_to_gen(imagedict)); continue; } - type = fz_dict_gets(imagedict, "Subtype"); - if (strcmp(fz_to_name(type), "Image")) + type = pdf_dict_gets(imagedict, "Subtype"); + if (strcmp(pdf_to_name(type), "Image")) continue; - filter = fz_dict_gets(imagedict, "Filter"); + filter = pdf_dict_gets(imagedict, "Filter"); altcs = NULL; - cs = fz_dict_gets(imagedict, "ColorSpace"); - if (fz_is_array(cs)) + cs = pdf_dict_gets(imagedict, "ColorSpace"); + if (pdf_is_array(cs)) { - fz_obj *cses = cs; + pdf_obj *cses = cs; - cs = fz_array_get(cses, 0); - if (fz_is_name(cs) && (!strcmp(fz_to_name(cs), "DeviceN") || !strcmp(fz_to_name(cs), "Separation"))) + cs = pdf_array_get(cses, 0); + if (pdf_is_name(cs) && (!strcmp(pdf_to_name(cs), "DeviceN") || !strcmp(pdf_to_name(cs), "Separation"))) { - altcs = fz_array_get(cses, 2); - if (fz_is_array(altcs)) - altcs = fz_array_get(altcs, 0); + altcs = pdf_array_get(cses, 2); + if (pdf_is_array(altcs)) + altcs = pdf_array_get(altcs, 0); } } - width = fz_dict_gets(imagedict, "Width"); - height = fz_dict_gets(imagedict, "Height"); - bpc = fz_dict_gets(imagedict, "BitsPerComponent"); + width = pdf_dict_gets(imagedict, "Width"); + height = pdf_dict_gets(imagedict, "Height"); + bpc = pdf_dict_gets(imagedict, "BitsPerComponent"); for (k = 0; k < images; k++) - if (!fz_objcmp(image[k].u.image.obj, imagedict)) + if (!pdf_objcmp(image[k].u.image.obj, imagedict)) break; if (k < images) @@ -340,42 +340,42 @@ gatherimages(int page, fz_obj *pageref, fz_obj *pageobj, fz_obj *dict) } static void -gatherforms(int page, fz_obj *pageref, fz_obj *pageobj, fz_obj *dict) +gatherforms(int page, pdf_obj *pageref, pdf_obj *pageobj, pdf_obj *dict) { int i, n; - n = fz_dict_len(dict); + n = pdf_dict_len(dict); for (i = 0; i < n; i++) { - fz_obj *xobjdict; - fz_obj *type; - fz_obj *subtype; - fz_obj *group; - fz_obj *groupsubtype; - fz_obj *reference; + pdf_obj *xobjdict; + pdf_obj *type; + pdf_obj *subtype; + pdf_obj *group; + pdf_obj *groupsubtype; + pdf_obj *reference; int k; - xobjdict = fz_dict_get_val(dict, i); - if (!fz_is_dict(xobjdict)) + xobjdict = pdf_dict_get_val(dict, i); + if (!pdf_is_dict(xobjdict)) { - fz_warn(ctx, "not a xobject dict (%d %d R)", fz_to_num(xobjdict), fz_to_gen(xobjdict)); + fz_warn(ctx, "not a xobject dict (%d %d R)", pdf_to_num(xobjdict), pdf_to_gen(xobjdict)); continue; } - type = fz_dict_gets(xobjdict, "Subtype"); - if (strcmp(fz_to_name(type), "Form")) + type = pdf_dict_gets(xobjdict, "Subtype"); + if (strcmp(pdf_to_name(type), "Form")) continue; - subtype = fz_dict_gets(xobjdict, "Subtype2"); - if (!strcmp(fz_to_name(subtype), "PS")) + subtype = pdf_dict_gets(xobjdict, "Subtype2"); + if (!strcmp(pdf_to_name(subtype), "PS")) continue; - group = fz_dict_gets(xobjdict, "Group"); - groupsubtype = fz_dict_gets(group, "S"); - reference = fz_dict_gets(xobjdict, "Ref"); + group = pdf_dict_gets(xobjdict, "Group"); + groupsubtype = pdf_dict_gets(group, "S"); + reference = pdf_dict_gets(xobjdict, "Ref"); for (k = 0; k < forms; k++) - if (!fz_objcmp(form[k].u.form.obj, xobjdict)) + if (!pdf_objcmp(form[k].u.form.obj, xobjdict)) break; if (k < forms) @@ -394,33 +394,33 @@ gatherforms(int page, fz_obj *pageref, fz_obj *pageobj, fz_obj *dict) } static void -gatherpsobjs(int page, fz_obj *pageref, fz_obj *pageobj, fz_obj *dict) +gatherpsobjs(int page, pdf_obj *pageref, pdf_obj *pageobj, pdf_obj *dict) { int i, n; - n = fz_dict_len(dict); + n = pdf_dict_len(dict); for (i = 0; i < n; i++) { - fz_obj *xobjdict; - fz_obj *type; - fz_obj *subtype; + pdf_obj *xobjdict; + pdf_obj *type; + pdf_obj *subtype; int k; - xobjdict = fz_dict_get_val(dict, i); - if (!fz_is_dict(xobjdict)) + xobjdict = pdf_dict_get_val(dict, i); + if (!pdf_is_dict(xobjdict)) { - fz_warn(ctx, "not a xobject dict (%d %d R)", fz_to_num(xobjdict), fz_to_gen(xobjdict)); + fz_warn(ctx, "not a xobject dict (%d %d R)", pdf_to_num(xobjdict), pdf_to_gen(xobjdict)); continue; } - type = fz_dict_gets(xobjdict, "Subtype"); - subtype = fz_dict_gets(xobjdict, "Subtype2"); - if (strcmp(fz_to_name(type), "PS") && - (strcmp(fz_to_name(type), "Form") || strcmp(fz_to_name(subtype), "PS"))) + type = pdf_dict_gets(xobjdict, "Subtype"); + subtype = pdf_dict_gets(xobjdict, "Subtype2"); + if (strcmp(pdf_to_name(type), "PS") && + (strcmp(pdf_to_name(type), "Form") || strcmp(pdf_to_name(subtype), "PS"))) continue; for (k = 0; k < psobjs; k++) - if (!fz_objcmp(psobj[k].u.form.obj, xobjdict)) + if (!pdf_objcmp(psobj[k].u.form.obj, xobjdict)) break; if (k < psobjs) @@ -437,33 +437,33 @@ gatherpsobjs(int page, fz_obj *pageref, fz_obj *pageobj, fz_obj *dict) } static void -gathershadings(int page, fz_obj *pageref, fz_obj *pageobj, fz_obj *dict) +gathershadings(int page, pdf_obj *pageref, pdf_obj *pageobj, pdf_obj *dict) { int i, n; - n = fz_dict_len(dict); + n = pdf_dict_len(dict); for (i = 0; i < n; i++) { - fz_obj *shade; - fz_obj *type; + pdf_obj *shade; + pdf_obj *type; int k; - shade = fz_dict_get_val(dict, i); - if (!fz_is_dict(shade)) + shade = pdf_dict_get_val(dict, i); + if (!pdf_is_dict(shade)) { - fz_warn(ctx, "not a shading dict (%d %d R)", fz_to_num(shade), fz_to_gen(shade)); + fz_warn(ctx, "not a shading dict (%d %d R)", pdf_to_num(shade), pdf_to_gen(shade)); continue; } - type = fz_dict_gets(shade, "ShadingType"); - if (!fz_is_int(type) || fz_to_int(type) < 1 || fz_to_int(type) > 7) + type = pdf_dict_gets(shade, "ShadingType"); + if (!pdf_is_int(type) || pdf_to_int(type) < 1 || pdf_to_int(type) > 7) { - fz_warn(ctx, "not a shading type (%d %d R)", fz_to_num(shade), fz_to_gen(shade)); + fz_warn(ctx, "not a shading type (%d %d R)", pdf_to_num(shade), pdf_to_gen(shade)); type = NULL; } for (k = 0; k < shadings; k++) - if (!fz_objcmp(shading[k].u.shading.obj, shade)) + if (!pdf_objcmp(shading[k].u.shading.obj, shade)) break; if (k < shadings) @@ -481,57 +481,57 @@ gathershadings(int page, fz_obj *pageref, fz_obj *pageobj, fz_obj *dict) } static void -gatherpatterns(int page, fz_obj *pageref, fz_obj *pageobj, fz_obj *dict) +gatherpatterns(int page, pdf_obj *pageref, pdf_obj *pageobj, pdf_obj *dict) { int i, n; - n = fz_dict_len(dict); + n = pdf_dict_len(dict); for (i = 0; i < n; i++) { - fz_obj *patterndict; - fz_obj *type; - fz_obj *paint = NULL; - fz_obj *tiling = NULL; - fz_obj *shading = NULL; + pdf_obj *patterndict; + pdf_obj *type; + pdf_obj *paint = NULL; + pdf_obj *tiling = NULL; + pdf_obj *shading = NULL; int k; - patterndict = fz_dict_get_val(dict, i); - if (!fz_is_dict(patterndict)) + patterndict = pdf_dict_get_val(dict, i); + if (!pdf_is_dict(patterndict)) { - fz_warn(ctx, "not a pattern dict (%d %d R)", fz_to_num(patterndict), fz_to_gen(patterndict)); + fz_warn(ctx, "not a pattern dict (%d %d R)", pdf_to_num(patterndict), pdf_to_gen(patterndict)); continue; } - type = fz_dict_gets(patterndict, "PatternType"); - if (!fz_is_int(type) || fz_to_int(type) < 1 || fz_to_int(type) > 2) + type = pdf_dict_gets(patterndict, "PatternType"); + if (!pdf_is_int(type) || pdf_to_int(type) < 1 || pdf_to_int(type) > 2) { - fz_warn(ctx, "not a pattern type (%d %d R)", fz_to_num(patterndict), fz_to_gen(patterndict)); + fz_warn(ctx, "not a pattern type (%d %d R)", pdf_to_num(patterndict), pdf_to_gen(patterndict)); type = NULL; } - if (fz_to_int(type) == 1) + if (pdf_to_int(type) == 1) { - paint = fz_dict_gets(patterndict, "PaintType"); - if (!fz_is_int(paint) || fz_to_int(paint) < 1 || fz_to_int(paint) > 2) + paint = pdf_dict_gets(patterndict, "PaintType"); + if (!pdf_is_int(paint) || pdf_to_int(paint) < 1 || pdf_to_int(paint) > 2) { - fz_warn(ctx, "not a pattern paint type (%d %d R)", fz_to_num(patterndict), fz_to_gen(patterndict)); + fz_warn(ctx, "not a pattern paint type (%d %d R)", pdf_to_num(patterndict), pdf_to_gen(patterndict)); paint = NULL; } - tiling = fz_dict_gets(patterndict, "TilingType"); - if (!fz_is_int(tiling) || fz_to_int(tiling) < 1 || fz_to_int(tiling) > 3) + tiling = pdf_dict_gets(patterndict, "TilingType"); + if (!pdf_is_int(tiling) || pdf_to_int(tiling) < 1 || pdf_to_int(tiling) > 3) { - fz_warn(ctx, "not a pattern tiling type (%d %d R)", fz_to_num(patterndict), fz_to_gen(patterndict)); + fz_warn(ctx, "not a pattern tiling type (%d %d R)", pdf_to_num(patterndict), pdf_to_gen(patterndict)); tiling = NULL; } } else { - shading = fz_dict_gets(patterndict, "Shading"); + shading = pdf_dict_gets(patterndict, "Shading"); } for (k = 0; k < patterns; k++) - if (!fz_objcmp(pattern[k].u.pattern.obj, patterndict)) + if (!pdf_objcmp(pattern[k].u.pattern.obj, patterndict)) break; if (k < patterns) @@ -552,15 +552,15 @@ gatherpatterns(int page, fz_obj *pageref, fz_obj *pageobj, fz_obj *dict) } static void -gatherresourceinfo(int page, fz_obj *rsrc) +gatherresourceinfo(int page, pdf_obj *rsrc) { - fz_obj *pageobj; - fz_obj *pageref; - fz_obj *font; - fz_obj *xobj; - fz_obj *shade; - fz_obj *pattern; - fz_obj *subrsrc; + pdf_obj *pageobj; + pdf_obj *pageref; + pdf_obj *font; + pdf_obj *xobj; + pdf_obj *shade; + pdf_obj *pattern; + pdf_obj *subrsrc; int i; pageobj = xref->page_objs[page-1]; @@ -569,24 +569,24 @@ gatherresourceinfo(int page, fz_obj *rsrc) if (!pageobj) fz_throw(ctx, "cannot retrieve info from page %d", page); - font = fz_dict_gets(rsrc, "Font"); + font = pdf_dict_gets(rsrc, "Font"); if (font) { int n; gatherfonts(page, pageref, pageobj, font); - n = fz_dict_len(font); + n = pdf_dict_len(font); for (i = 0; i < n; i++) { - fz_obj *obj = fz_dict_get_val(font, i); + pdf_obj *obj = pdf_dict_get_val(font, i); - subrsrc = fz_dict_gets(obj, "Resources"); - if (subrsrc && fz_objcmp(rsrc, subrsrc)) + subrsrc = pdf_dict_gets(obj, "Resources"); + if (subrsrc && pdf_objcmp(rsrc, subrsrc)) gatherresourceinfo(page, subrsrc); } } - xobj = fz_dict_gets(rsrc, "XObject"); + xobj = pdf_dict_gets(rsrc, "XObject"); if (xobj) { int n; @@ -594,31 +594,31 @@ gatherresourceinfo(int page, fz_obj *rsrc) gatherimages(page, pageref, pageobj, xobj); gatherforms(page, pageref, pageobj, xobj); gatherpsobjs(page, pageref, pageobj, xobj); - n = fz_dict_len(xobj); + n = pdf_dict_len(xobj); for (i = 0; i < n; i++) { - fz_obj *obj = fz_dict_get_val(xobj, i); - subrsrc = fz_dict_gets(obj, "Resources"); - if (subrsrc && fz_objcmp(rsrc, subrsrc)) + pdf_obj *obj = pdf_dict_get_val(xobj, i); + subrsrc = pdf_dict_gets(obj, "Resources"); + if (subrsrc && pdf_objcmp(rsrc, subrsrc)) gatherresourceinfo(page, subrsrc); } } - shade = fz_dict_gets(rsrc, "Shading"); + shade = pdf_dict_gets(rsrc, "Shading"); if (shade) gathershadings(page, pageref, pageobj, shade); - pattern = fz_dict_gets(rsrc, "Pattern"); + pattern = pdf_dict_gets(rsrc, "Pattern"); if (pattern) { int n; gatherpatterns(page, pageref, pageobj, pattern); - n = fz_dict_len(pattern); + n = pdf_dict_len(pattern); for (i = 0; i < n; i++) { - fz_obj *obj = fz_dict_get_val(pattern, i); - subrsrc = fz_dict_gets(obj, "Resources"); - if (subrsrc && fz_objcmp(rsrc, subrsrc)) + pdf_obj *obj = pdf_dict_get_val(pattern, i); + subrsrc = pdf_dict_gets(obj, "Resources"); + if (subrsrc && pdf_objcmp(rsrc, subrsrc)) gatherresourceinfo(page, subrsrc); } } @@ -627,9 +627,9 @@ gatherresourceinfo(int page, fz_obj *rsrc) static void gatherpageinfo(int page) { - fz_obj *pageobj; - fz_obj *pageref; - fz_obj *rsrc; + pdf_obj *pageobj; + pdf_obj *pageref; + pdf_obj *rsrc; pageobj = xref->page_objs[page-1]; pageref = xref->page_refs[page-1]; @@ -639,7 +639,7 @@ gatherpageinfo(int page) gatherdimensions(page, pageref, pageobj); - rsrc = fz_dict_gets(pageobj, "Resources"); + rsrc = pdf_dict_gets(pageobj, "Resources"); gatherresourceinfo(page, rsrc); } @@ -658,7 +658,7 @@ printinfo(char *filename, int show, int page) { printf(PAGE_FMT "[ %g %g %g %g ]\n", dim[i].page, - fz_to_num(dim[i].pageref), fz_to_gen(dim[i].pageref), + pdf_to_num(dim[i].pageref), pdf_to_gen(dim[i].pageref), dim[i].u.dim.bbox->x0, dim[i].u.dim.bbox->y0, dim[i].u.dim.bbox->x1, @@ -674,10 +674,10 @@ printinfo(char *filename, int show, int page) { printf(PAGE_FMT "%s '%s' (%d %d R)\n", font[i].page, - fz_to_num(font[i].pageref), fz_to_gen(font[i].pageref), - fz_to_name(font[i].u.font.subtype), - fz_to_name(font[i].u.font.name), - fz_to_num(font[i].u.font.obj), fz_to_gen(font[i].u.font.obj)); + pdf_to_num(font[i].pageref), pdf_to_gen(font[i].pageref), + pdf_to_name(font[i].u.font.subtype), + pdf_to_name(font[i].u.font.name), + pdf_to_num(font[i].u.font.obj), pdf_to_gen(font[i].u.font.obj)); } printf("\n"); } @@ -692,29 +692,29 @@ printinfo(char *filename, int show, int page) printf(PAGE_FMT "[ ", image[i].page, - fz_to_num(image[i].pageref), fz_to_gen(image[i].pageref)); + pdf_to_num(image[i].pageref), pdf_to_gen(image[i].pageref)); - if (fz_is_array(image[i].u.image.filter)) + if (pdf_is_array(image[i].u.image.filter)) { - int n = fz_array_len(image[i].u.image.filter); + int n = pdf_array_len(image[i].u.image.filter); for (j = 0; j < n; j++) { - fz_obj *obj = fz_array_get(image[i].u.image.filter, j); - char *filter = fz_strdup(ctx, fz_to_name(obj)); + pdf_obj *obj = pdf_array_get(image[i].u.image.filter, j); + char *filter = fz_strdup(ctx, pdf_to_name(obj)); if (strstr(filter, "Decode")) *(strstr(filter, "Decode")) = '\0'; printf("%s%s", filter, - j == fz_array_len(image[i].u.image.filter) - 1 ? "" : " "); + j == pdf_array_len(image[i].u.image.filter) - 1 ? "" : " "); fz_free(ctx, filter); } } else if (image[i].u.image.filter) { - fz_obj *obj = image[i].u.image.filter; - char *filter = fz_strdup(ctx, fz_to_name(obj)); + pdf_obj *obj = image[i].u.image.filter; + char *filter = fz_strdup(ctx, pdf_to_name(obj)); if (strstr(filter, "Decode")) *(strstr(filter, "Decode")) = '\0'; @@ -727,7 +727,7 @@ printinfo(char *filename, int show, int page) if (image[i].u.image.cs) { - cs = fz_strdup(ctx, fz_to_name(image[i].u.image.cs)); + cs = fz_strdup(ctx, pdf_to_name(image[i].u.image.cs)); if (!strncmp(cs, "Device", 6)) { @@ -746,7 +746,7 @@ printinfo(char *filename, int show, int page) } if (image[i].u.image.altcs) { - altcs = fz_strdup(ctx, fz_to_name(image[i].u.image.altcs)); + altcs = fz_strdup(ctx, pdf_to_name(image[i].u.image.altcs)); if (!strncmp(altcs, "Device", 6)) { @@ -765,13 +765,13 @@ printinfo(char *filename, int show, int page) } printf(" ] %dx%d %dbpc %s%s%s (%d %d R)\n", - fz_to_int(image[i].u.image.width), - fz_to_int(image[i].u.image.height), - image[i].u.image.bpc ? fz_to_int(image[i].u.image.bpc) : 1, + pdf_to_int(image[i].u.image.width), + pdf_to_int(image[i].u.image.height), + image[i].u.image.bpc ? pdf_to_int(image[i].u.image.bpc) : 1, image[i].u.image.cs ? cs : "ImageMask", image[i].u.image.altcs ? " " : "", image[i].u.image.altcs ? altcs : "", - fz_to_num(image[i].u.image.obj), fz_to_gen(image[i].u.image.obj)); + pdf_to_num(image[i].u.image.obj), pdf_to_gen(image[i].u.image.obj)); fz_free(ctx, cs); fz_free(ctx, altcs); @@ -798,9 +798,9 @@ printinfo(char *filename, int show, int page) printf(PAGE_FMT "%s (%d %d R)\n", shading[i].page, - fz_to_num(shading[i].pageref), fz_to_gen(shading[i].pageref), - shadingtype[fz_to_int(shading[i].u.shading.type)], - fz_to_num(shading[i].u.shading.obj), fz_to_gen(shading[i].u.shading.obj)); + pdf_to_num(shading[i].pageref), pdf_to_gen(shading[i].pageref), + shadingtype[pdf_to_int(shading[i].u.shading.type)], + pdf_to_num(shading[i].u.shading.obj), pdf_to_gen(shading[i].u.shading.obj)); } printf("\n"); } @@ -810,7 +810,7 @@ printinfo(char *filename, int show, int page) printf("Patterns (%d):\n", patterns); for (i = 0; i < patterns; i++) { - if (fz_to_int(pattern[i].u.pattern.type) == 1) + if (pdf_to_int(pattern[i].u.pattern.type) == 1) { char *painttype[] = { @@ -828,18 +828,18 @@ printinfo(char *filename, int show, int page) printf(PAGE_FMT "Tiling %s %s (%d %d R)\n", pattern[i].page, - fz_to_num(pattern[i].pageref), fz_to_gen(pattern[i].pageref), - painttype[fz_to_int(pattern[i].u.pattern.paint)], - tilingtype[fz_to_int(pattern[i].u.pattern.tiling)], - fz_to_num(pattern[i].u.pattern.obj), fz_to_gen(pattern[i].u.pattern.obj)); + pdf_to_num(pattern[i].pageref), pdf_to_gen(pattern[i].pageref), + painttype[pdf_to_int(pattern[i].u.pattern.paint)], + tilingtype[pdf_to_int(pattern[i].u.pattern.tiling)], + pdf_to_num(pattern[i].u.pattern.obj), pdf_to_gen(pattern[i].u.pattern.obj)); } else { printf(PAGE_FMT "Shading %d %d R (%d %d R)\n", pattern[i].page, - fz_to_num(pattern[i].pageref), fz_to_gen(pattern[i].pageref), - fz_to_num(pattern[i].u.pattern.shading), fz_to_gen(pattern[i].u.pattern.shading), - fz_to_num(pattern[i].u.pattern.obj), fz_to_gen(pattern[i].u.pattern.obj)); + pdf_to_num(pattern[i].pageref), pdf_to_gen(pattern[i].pageref), + pdf_to_num(pattern[i].u.pattern.shading), pdf_to_gen(pattern[i].u.pattern.shading), + pdf_to_num(pattern[i].u.pattern.obj), pdf_to_gen(pattern[i].u.pattern.obj)); } } printf("\n"); @@ -852,12 +852,12 @@ printinfo(char *filename, int show, int page) { printf(PAGE_FMT "Form%s%s%s%s (%d %d R)\n", form[i].page, - fz_to_num(form[i].pageref), fz_to_gen(form[i].pageref), + pdf_to_num(form[i].pageref), pdf_to_gen(form[i].pageref), form[i].u.form.groupsubtype ? " " : "", - form[i].u.form.groupsubtype ? fz_to_name(form[i].u.form.groupsubtype) : "", + form[i].u.form.groupsubtype ? pdf_to_name(form[i].u.form.groupsubtype) : "", form[i].u.form.groupsubtype ? " Group" : "", form[i].u.form.reference ? " Reference" : "", - fz_to_num(form[i].u.form.obj), fz_to_gen(form[i].u.form.obj)); + pdf_to_num(form[i].u.form.obj), pdf_to_gen(form[i].u.form.obj)); } printf("\n"); } @@ -869,8 +869,8 @@ printinfo(char *filename, int show, int page) { printf(PAGE_FMT "(%d %d R)\n", psobj[i].page, - fz_to_num(psobj[i].pageref), fz_to_gen(psobj[i].pageref), - fz_to_num(psobj[i].u.form.obj), fz_to_gen(psobj[i].u.form.obj)); + pdf_to_num(psobj[i].pageref), pdf_to_gen(psobj[i].pageref), + pdf_to_num(psobj[i].u.form.obj), pdf_to_gen(psobj[i].u.form.obj)); } printf("\n"); } @@ -996,7 +996,7 @@ int main(int argc, char **argv) xref = pdf_open_document(ctx, filename); if (pdf_needs_password(xref)) if (!pdf_authenticate_password(xref, password)) - fz_throw(ctx, "cannot authenticate password: %s\n", filename); + fz_throw(ctx, "cannot authenticate password: %s", filename); pagecount = pdf_count_pages(xref); showglobalinfo(); diff --git a/apps/mupdfshow.c b/apps/mupdfshow.c index 8dcdd17d..70ca7a62 100644 --- a/apps/mupdfshow.c +++ b/apps/mupdfshow.c @@ -2,8 +2,7 @@ * pdfshow -- the ultimate pdf debugging tool */ -#include "fitz.h" -#include "mupdf.h" +#include "mupdf-internal.h" static pdf_document *doc = NULL; static fz_context *ctx = NULL; @@ -25,7 +24,7 @@ static void showtrailer(void) if (!doc) fz_throw(ctx, "no file specified"); printf("trailer\n"); - fz_debug_obj(doc->trailer); + pdf_print_obj(doc->trailer); printf("\n"); } @@ -33,13 +32,13 @@ static void showxref(void) { if (!doc) fz_throw(ctx, "no file specified"); - pdf_debug_xref(doc); + pdf_print_xref(doc); printf("\n"); } static void showpagetree(void) { - fz_obj *ref; + pdf_obj *ref; int count; int i; @@ -50,7 +49,7 @@ static void showpagetree(void) for (i = 0; i < count; i++) { ref = doc->page_refs[i]; - printf("page %d = %d %d R\n", i + 1, fz_to_num(ref), fz_to_gen(ref)); + printf("page %d = %d %d R\n", i + 1, pdf_to_num(ref), pdf_to_gen(ref)); } printf("\n"); } @@ -107,7 +106,7 @@ static void showstream(int num, int gen) static void showobject(int num, int gen) { - fz_obj *obj; + pdf_obj *obj; if (!doc) fz_throw(ctx, "no file specified"); @@ -123,7 +122,7 @@ static void showobject(int num, int gen) else { printf("%d %d obj\n", num, gen); - fz_debug_obj(obj); + pdf_print_obj(obj); printf("stream\n"); showstream(num, gen); printf("endstream\n"); @@ -133,19 +132,19 @@ static void showobject(int num, int gen) else { printf("%d %d obj\n", num, gen); - fz_debug_obj(obj); + pdf_print_obj(obj); printf("endobj\n\n"); } - fz_drop_obj(obj); + pdf_drop_obj(obj); } static void showgrep(char *filename) { - fz_obj *obj; + pdf_obj *obj; int i; - for (i = 0; i < doc->len; i++) + for (i = 0; i < pdf_count_objects(doc); i++) { if (doc->table[i].type == 'n' || doc->table[i].type == 'o') { @@ -159,17 +158,17 @@ static void showgrep(char *filename) continue; } - fz_sort_dict(obj); + pdf_sort_dict(obj); printf("%s:%d: ", filename, i); - fz_fprint_obj(stdout, obj, 1); + pdf_fprint_obj(stdout, obj, 1); - fz_drop_obj(obj); + pdf_drop_obj(obj); } } printf("%s:trailer: ", filename); - fz_fprint_obj(stdout, doc->trailer, 1); + pdf_fprint_obj(stdout, doc->trailer, 1); } #ifdef MUPDF_COMBINED_EXE diff --git a/apps/pdfapp.c b/apps/pdfapp.c index 6f2d766d..acad7c9f 100644 --- a/apps/pdfapp.c +++ b/apps/pdfapp.c @@ -1,8 +1,7 @@ -#include "fitz.h" +#include "pdfapp.h" #include "mupdf.h" #include "muxps.h" #include "mucbz.h" -#include "pdfapp.h" #include <ctype.h> /* for tolower() */ @@ -80,23 +79,7 @@ void pdfapp_init(fz_context *ctx, pdfapp_t *app) void pdfapp_invert(pdfapp_t *app, fz_bbox rect) { - unsigned char *p; - int x, y, n; - - int x0 = CLAMP(rect.x0 - app->image->x, 0, app->image->w - 1); - int x1 = CLAMP(rect.x1 - app->image->x, 0, app->image->w - 1); - int y0 = CLAMP(rect.y0 - app->image->y, 0, app->image->h - 1); - int y1 = CLAMP(rect.y1 - app->image->y, 0, app->image->h - 1); - - for (y = y0; y < y1; y++) - { - p = app->image->samples + (y * app->image->w + x0) * app->image->n; - for (x = x0; x < x1; x++) - { - for (n = app->image->n; n > 0; n--, p++) - *p = 255 - *p; - } - } + fz_invert_pixmap_rect(app->image, rect); } void pdfapp_open(pdfapp_t *app, char *filename, int fd, int reload) @@ -174,7 +157,7 @@ void pdfapp_close(pdfapp_t *app) app->page_list = NULL; if (app->page_text) - fz_free_text_span(app->ctx, app->page_text); + fz_free_text_page(app->ctx, app->page_text); app->page_text = NULL; if (app->page_links) @@ -216,20 +199,23 @@ static fz_matrix pdfapp_viewctm(pdfapp_t *app) static void pdfapp_panview(pdfapp_t *app, int newx, int newy) { + int image_w = fz_pixmap_width(app->ctx, app->image); + int image_h = fz_pixmap_height(app->ctx, app->image); + if (newx > 0) newx = 0; if (newy > 0) newy = 0; - if (newx + app->image->w < app->winw) - newx = app->winw - app->image->w; - if (newy + app->image->h < app->winh) - newy = app->winh - app->image->h; + if (newx + image_w < app->winw) + newx = app->winw - image_w; + if (newy + image_h < app->winh) + newy = app->winh - image_h; - if (app->winw >= app->image->w) - newx = (app->winw - app->image->w) / 2; - if (app->winh >= app->image->h) - newy = (app->winh - app->image->h) / 2; + if (app->winw >= image_w) + newx = (app->winw - image_w) / 2; + if (app->winh >= image_h) + newy = (app->winh - image_h) / 2; if (newx != app->panx || newy != app->pany) winrepaint(app); @@ -245,7 +231,7 @@ static void pdfapp_loadpage(pdfapp_t *app) if (app->page_list) fz_free_display_list(app->ctx, app->page_list); if (app->page_text) - fz_free_text_span(app->ctx, app->page_text); + fz_free_text_page(app->ctx, app->page_text); if (app->page_links) fz_drop_link(app->ctx, app->page_links); if (app->page) @@ -270,9 +256,11 @@ static void pdfapp_loadpage(pdfapp_t *app) } } +#define MAX_TITLE 256 + static void pdfapp_showpage(pdfapp_t *app, int loadpage, int drawpage, int repaint) { - char buf[256]; + char buf[MAX_TITLE]; fz_device *idev; fz_device *tdev; fz_colorspace *colorspace; @@ -290,16 +278,29 @@ static void pdfapp_showpage(pdfapp_t *app, int loadpage, int drawpage, int repai app->hitlen = 0; /* Extract text */ - app->page_text = fz_new_text_span(app->ctx); - tdev = fz_new_text_device(app->ctx, app->page_text); + app->page_sheet = fz_new_text_sheet(app->ctx); + app->page_text = fz_new_text_page(app->ctx, app->page_bbox); + tdev = fz_new_text_device(app->ctx, app->page_sheet, app->page_text); fz_run_display_list(app->page_list, tdev, fz_identity, fz_infinite_bbox, NULL); fz_free_device(tdev); } if (drawpage) { - sprintf(buf, "%s - %d/%d (%d dpi)", app->doctitle, + char buf2[64]; + int len; + + sprintf(buf2, " - %d/%d (%d dpi)", app->pageno, app->pagecount, app->resolution); + len = MAX_TITLE-strlen(buf2); + if (strlen(app->doctitle) > len) + { + snprintf(buf, len-3, "%s", app->doctitle); + strcat(buf, "..."); + strcat(buf, buf2); + } + else + sprintf(buf, "%s%s", app->doctitle, buf2); wintitle(app, buf); ctm = pdfapp_viewctm(app); @@ -316,7 +317,7 @@ static void pdfapp_showpage(pdfapp_t *app, int loadpage, int drawpage, int repai #else colorspace = fz_device_rgb; #endif - app->image = fz_new_pixmap_with_rect(app->ctx, colorspace, bbox); + app->image = fz_new_pixmap_with_bbox(app->ctx, colorspace, bbox); fz_clear_pixmap_with_value(app->ctx, app->image, 255); idev = fz_new_draw_device(app->ctx, app->image); fz_run_display_list(app->page_list, idev, ctm, bbox, NULL); @@ -329,8 +330,8 @@ static void pdfapp_showpage(pdfapp_t *app, int loadpage, int drawpage, int repai if (app->shrinkwrap) { - int w = app->image->w; - int h = app->image->h; + int w = fz_pixmap_width(app->ctx, app->image); + int h = fz_pixmap_height(app->ctx, app->image); if (app->winw == w) app->panx = 0; if (app->winh == h) @@ -371,23 +372,61 @@ static void pdfapp_gotopage(pdfapp_t *app, int number) pdfapp_showpage(app, 1, 1, 1); } -static inline fz_bbox bboxcharat(fz_text_span *span, int idx) +static fz_text_char textcharat(fz_text_page *page, int idx) { + static fz_text_char emptychar = { {0,0,0,0}, ' ' }; + fz_text_block *block; + fz_text_line *line; + fz_text_span *span; int ofs = 0; - while (span) + for (block = page->blocks; block < page->blocks + page->len; block++) + { + for (line = block->lines; line < block->lines + block->len; line++) + { + for (span = line->spans; span < line->spans + line->len; span++) + { + if (idx < ofs + span->len) + return span->text[idx - ofs]; + /* pseudo-newline */ + if (span + 1 == line->spans + line->len) + { + if (idx == ofs + span->len) + return emptychar; + ofs++; + } + ofs += span->len; + } + } + } + return emptychar; +} + +static int textlen(fz_text_page *page) +{ + fz_text_block *block; + fz_text_line *line; + fz_text_span *span; + int len = 0; + for (block = page->blocks; block < page->blocks + page->len; block++) { - if (idx < ofs + span->len) - return span->text[idx - ofs].bbox; - if (span->eol) + for (line = block->lines; line < block->lines + block->len; line++) { - if (idx == ofs + span->len) - return fz_empty_bbox; - ofs ++; + for (span = line->spans; span < line->spans + line->len; span++) + len += span->len; + len++; /* pseudo-newline */ } - ofs += span->len; - span = span->next; } - return fz_empty_bbox; + return len; +} + +static inline int charat(fz_text_page *page, int idx) +{ + return textcharat(page, idx).c; +} + +static inline fz_bbox bboxcharat(fz_text_page *page, int idx) +{ + return fz_round_rect(textcharat(page, idx).bbox); } void pdfapp_inverthit(pdfapp_t *app) @@ -421,52 +460,20 @@ void pdfapp_inverthit(pdfapp_t *app) pdfapp_invert(app, fz_transform_bbox(ctm, hitbox)); } -static inline int charat(fz_text_span *span, int idx) -{ - int ofs = 0; - while (span) - { - if (idx < ofs + span->len) - return span->text[idx - ofs].c; - if (span->eol) - { - if (idx == ofs + span->len) - return ' '; - ofs ++; - } - ofs += span->len; - span = span->next; - } - return 0; -} - -static int textlen(fz_text_span *span) -{ - int len = 0; - while (span) - { - len += span->len; - if (span->eol) - len ++; - span = span->next; - } - return len; -} - -static int match(char *s, fz_text_span *span, int n) +static int match(char *s, fz_text_page *page, int n) { int orig = n; int c; while ((c = *s++)) { - if (c == ' ' && charat(span, n) == ' ') + if (c == ' ' && charat(page, n) == ' ') { - while (charat(span, n) == ' ') + while (charat(page, n) == ' ') n++; } else { - if (tolower(c) != tolower(charat(span, n))) + if (tolower(c) != tolower(charat(page, n))) return 0; n++; } @@ -721,22 +728,22 @@ void pdfapp_onkey(pdfapp_t *app, int c) break; case 'h': - app->panx += app->image->w / 10; + app->panx += fz_pixmap_width(app->ctx, app->image) / 10; pdfapp_showpage(app, 0, 0, 1); break; case 'j': - app->pany -= app->image->h / 10; + app->pany -= fz_pixmap_height(app->ctx, app->image) / 10; pdfapp_showpage(app, 0, 0, 1); break; case 'k': - app->pany += app->image->h / 10; + app->pany += fz_pixmap_height(app->ctx, app->image) / 10; pdfapp_showpage(app, 0, 0, 1); break; case 'l': - app->panx -= app->image->w / 10; + app->panx -= fz_pixmap_width(app->ctx, app->image) / 10; pdfapp_showpage(app, 0, 0, 1); break; @@ -911,12 +918,13 @@ void pdfapp_onkey(pdfapp_t *app, int c) void pdfapp_onmouse(pdfapp_t *app, int x, int y, int btn, int modifiers, int state) { + fz_bbox rect = fz_pixmap_bbox(app->ctx, app->image); fz_link *link; fz_matrix ctm; fz_point p; - p.x = x - app->panx + app->image->x; - p.y = y - app->pany + app->image->y; + p.x = x - app->panx + rect.x0; + p.y = y - app->pany + rect.y0; ctm = pdfapp_viewctm(app); ctm = fz_invert_matrix(ctm); @@ -1000,10 +1008,10 @@ void pdfapp_onmouse(pdfapp_t *app, int x, int y, int btn, int modifiers, int sta if (app->iscopying) { app->iscopying = 0; - app->selr.x0 = MIN(app->selx, x) - app->panx + app->image->x; - app->selr.x1 = MAX(app->selx, x) - app->panx + app->image->x; - app->selr.y0 = MIN(app->sely, y) - app->pany + app->image->y; - app->selr.y1 = MAX(app->sely, y) - app->pany + app->image->y; + app->selr.x0 = MIN(app->selx, x) - app->panx + rect.x0; + app->selr.x1 = MAX(app->selx, x) - app->panx + rect.x0; + app->selr.y0 = MIN(app->sely, y) - app->pany + rect.y0; + app->selr.y1 = MAX(app->sely, y) - app->pany + rect.y0; winrepaint(app); if (app->selr.x0 < app->selr.x1 && app->selr.y0 < app->selr.y1) windocopy(app); @@ -1018,7 +1026,7 @@ void pdfapp_onmouse(pdfapp_t *app, int x, int y, int btn, int modifiers, int sta int newy = app->pany + y - app->sely; /* Scrolling beyond limits implies flipping pages */ /* Are we requested to scroll beyond limits? */ - if (newy + app->image->h < app->winh || newy > 0) + if (newy + fz_pixmap_height(app->ctx, app->image) < app->winh || newy > 0) { /* Yes. We can assume that deltay != 0 */ int deltay = y - app->sely; @@ -1040,7 +1048,7 @@ void pdfapp_onmouse(pdfapp_t *app, int x, int y, int btn, int modifiers, int sta { app->pageno--; pdfapp_showpage(app, 1, 1, 1); - newy = -app->image->h; + newy = -fz_pixmap_height(app->ctx, app->image); } app->beyondy = 0; } @@ -1071,10 +1079,10 @@ void pdfapp_onmouse(pdfapp_t *app, int x, int y, int btn, int modifiers, int sta else if (app->iscopying) { - app->selr.x0 = MIN(app->selx, x) - app->panx + app->image->x; - app->selr.x1 = MAX(app->selx, x) - app->panx + app->image->x; - app->selr.y0 = MIN(app->sely, y) - app->pany + app->image->y; - app->selr.y1 = MAX(app->sely, y) - app->pany + app->image->y; + app->selr.x0 = MIN(app->selx, x) - app->panx + rect.x0; + app->selr.x1 = MAX(app->selx, x) - app->panx + rect.x0; + app->selr.y0 = MIN(app->sely, y) - app->pany + rect.y0; + app->selr.y1 = MAX(app->sely, y) - app->pany + rect.y0; winrepaint(app); } @@ -1084,6 +1092,9 @@ void pdfapp_oncopy(pdfapp_t *app, unsigned short *ucsbuf, int ucslen) { fz_bbox hitbox; fz_matrix ctm; + fz_text_page *page = app->page_text; + fz_text_block *block; + fz_text_line *line; fz_text_span *span; int c, i, p; int seen; @@ -1096,32 +1107,40 @@ void pdfapp_oncopy(pdfapp_t *app, unsigned short *ucsbuf, int ucslen) ctm = pdfapp_viewctm(app); p = 0; - for (span = app->page_text; span; span = span->next) - { - seen = 0; - for (i = 0; i < span->len; i++) + for (block = page->blocks; block < page->blocks + page->len; block++) + { + for (line = block->lines; line < block->lines + block->len; line++) { - hitbox = fz_transform_bbox(ctm, span->text[i].bbox); - c = span->text[i].c; - if (c < 32) - c = '?'; - if (hitbox.x1 >= x0 && hitbox.x0 <= x1 && hitbox.y1 >= y0 && hitbox.y0 <= y1) + for (span = line->spans; span < line->spans + line->len; span++) { - if (p < ucslen - 1) - ucsbuf[p++] = c; - seen = 1; - } - } + seen = 0; - if (seen && span->eol) - { + for (i = 0; i < span->len; i++) + { + hitbox = fz_round_rect(span->text[i].bbox); + hitbox = fz_transform_bbox(ctm, hitbox); + c = span->text[i].c; + if (c < 32) + c = '?'; + if (hitbox.x1 >= x0 && hitbox.x0 <= x1 && hitbox.y1 >= y0 && hitbox.y0 <= y1) + { + if (p < ucslen - 1) + ucsbuf[p++] = c; + seen = 1; + } + } + + if (seen && span + 1 == line->spans + line->len) + { #ifdef _WIN32 - if (p < ucslen - 1) - ucsbuf[p++] = '\r'; + if (p < ucslen - 1) + ucsbuf[p++] = '\r'; #endif - if (p < ucslen - 1) - ucsbuf[p++] = '\n'; + if (p < ucslen - 1) + ucsbuf[p++] = '\n'; + } + } } } diff --git a/apps/pdfapp.h b/apps/pdfapp.h index bb067bb4..db83335f 100644 --- a/apps/pdfapp.h +++ b/apps/pdfapp.h @@ -1,3 +1,8 @@ +#ifndef PDFAPP_H +#define PDFAPP_H + +#include "fitz.h" + /* * Utility object for handling a pdf application / view * Takes care of PDF loading and displaying and navigation, @@ -47,7 +52,8 @@ struct pdfapp_s fz_page *page; fz_rect page_bbox; fz_display_list *page_list; - fz_text_span *page_text; + fz_text_page *page_text; + fz_text_sheet *page_sheet; fz_link *page_links; /* snapback history */ @@ -106,3 +112,5 @@ void pdfapp_onresize(pdfapp_t *app, int w, int h); void pdfapp_invert(pdfapp_t *app, fz_bbox rect); void pdfapp_inverthit(pdfapp_t *app); + +#endif diff --git a/apps/win_main.c b/apps/win_main.c index c87faa97..37864e19 100644 --- a/apps/win_main.c +++ b/apps/win_main.c @@ -317,7 +317,7 @@ void wintitle(pdfapp_t *app, char *title) sp = title; while (*sp && dp < wide + 255) { - sp += chartorune(&rune, sp); + sp += fz_chartorune(&rune, sp); *dp++ = rune; } *dp = 0; @@ -355,10 +355,14 @@ void winblitsearch() void winblit() { + int image_w = fz_pixmap_width(gapp.ctx, gapp.image); + int image_h = fz_pixmap_height(gapp.ctx, gapp.image); + int image_n = fz_pixmap_components(context, gapp.image); + unsigned char *samples = fz_pixmap_samples(context, gapp.image); int x0 = gapp.panx; int y0 = gapp.pany; - int x1 = gapp.panx + gapp.image->w; - int y1 = gapp.pany + gapp.image->h; + int x1 = gapp.panx + image_w; + int y1 = gapp.pany + image_h; RECT r; if (gapp.image) @@ -371,15 +375,15 @@ void winblit() pdfapp_inverthit(&gapp); - dibinf->bmiHeader.biWidth = gapp.image->w; - dibinf->bmiHeader.biHeight = -gapp.image->h; - dibinf->bmiHeader.biSizeImage = gapp.image->h * 4; + dibinf->bmiHeader.biWidth = image_w; + dibinf->bmiHeader.biHeight = -image_h; + dibinf->bmiHeader.biSizeImage = image_h * 4; - if (gapp.image->n == 2) + if (image_n == 2) { - int i = gapp.image->w * gapp.image->h; + int i = image_w * image_h; unsigned char *color = malloc(i*4); - unsigned char *s = gapp.image->samples; + unsigned char *s = samples; unsigned char *d = color; for (; i > 0 ; i--) { @@ -388,16 +392,16 @@ void winblit() d += 4; } SetDIBitsToDevice(hdc, - gapp.panx, gapp.pany, gapp.image->w, gapp.image->h, - 0, 0, 0, gapp.image->h, color, + gapp.panx, gapp.pany, image_w, image_h, + 0, 0, 0, image_h, color, dibinf, DIB_RGB_COLORS); free(color); } - if (gapp.image->n == 4) + if (image_n == 4) { SetDIBitsToDevice(hdc, - gapp.panx, gapp.pany, gapp.image->w, gapp.image->h, - 0, 0, 0, gapp.image->h, gapp.image->samples, + gapp.panx, gapp.pany, image_w, image_h, + 0, 0, 0, image_h, samples, dibinf, DIB_RGB_COLORS); } diff --git a/apps/x11_image.c b/apps/x11_image.c index 35b32c7e..06764313 100644 --- a/apps/x11_image.c +++ b/apps/x11_image.c @@ -22,6 +22,12 @@ extern int ffs(int); +static int is_big_endian(void) +{ + static const int one = 1; + return *(char*)&one == 0; +} + typedef void (*ximage_convert_func_t) ( const unsigned char *src, @@ -212,7 +218,7 @@ select_mode(void) unsigned long rs, gs, bs; byteorder = ImageByteOrder(info.display); - if (fz_is_big_endian()) + if (is_big_endian()) byterev = byteorder != MSBFirst; else byterev = byteorder != LSBFirst; diff --git a/apps/x11_main.c b/apps/x11_main.c index 281618ef..447ebeb2 100644 --- a/apps/x11_main.c +++ b/apps/x11_main.c @@ -1,7 +1,3 @@ -#include "fitz.h" -#include "mupdf.h" -#include "muxps.h" -#include "mucbz.h" #include "pdfapp.h" #include <X11/Xlib.h> @@ -253,6 +249,8 @@ void winhelp(pdfapp_t *app) void winresize(pdfapp_t *app, int w, int h) { + int image_w = fz_pixmap_width(gapp.ctx, gapp.image); + int image_h = fz_pixmap_height(gapp.ctx, gapp.image); XWindowChanges values; int mask, width, height; @@ -287,7 +285,7 @@ void winresize(pdfapp_t *app, int w, int h) } XSetForeground(xdpy, xgc, WhitePixel(xdpy, xscr)); - XFillRectangle(xdpy, xwin, xgc, 0, 0, gapp.image->w, gapp.image->h); + XFillRectangle(xdpy, xwin, xgc, 0, 0, image_w, image_h); XFlush(xdpy); if (width != reqw || height != reqh) @@ -338,10 +336,14 @@ static void winblitsearch(pdfapp_t *app) static void winblit(pdfapp_t *app) { + int image_w = fz_pixmap_width(gapp.ctx, gapp.image); + int image_h = fz_pixmap_height(gapp.ctx, gapp.image); + int image_n = fz_pixmap_components(gapp.ctx, gapp.image); + unsigned char *image_samples = fz_pixmap_samples(gapp.ctx, gapp.image); int x0 = gapp.panx; int y0 = gapp.pany; - int x1 = gapp.panx + gapp.image->w; - int y1 = gapp.pany + gapp.image->h; + int x1 = gapp.panx + image_w; + int y1 = gapp.pany + image_h; XSetForeground(xdpy, xgc, xbgcolor.pixel); fillrect(0, 0, x0, gapp.winh); @@ -350,8 +352,8 @@ static void winblit(pdfapp_t *app) fillrect(0, y1, gapp.winw, gapp.winh - y1); XSetForeground(xdpy, xgc, xshcolor.pixel); - fillrect(x0+2, y1, gapp.image->w, 2); - fillrect(x1, y0+2, 2, gapp.image->h); + fillrect(x0+2, y1, image_w, 2); + fillrect(x1, y0+2, 2, image_h); if (gapp.iscopying || justcopied) { @@ -361,21 +363,21 @@ static void winblit(pdfapp_t *app) pdfapp_inverthit(&gapp); - if (gapp.image->n == 4) + if (image_n == 4) ximage_blit(xwin, xgc, x0, y0, - gapp.image->samples, + image_samples, 0, 0, - gapp.image->w, - gapp.image->h, - gapp.image->w * gapp.image->n); - else if (gapp.image->n == 2) + image_w, + image_h, + image_w * image_n); + else if (image_n == 2) { - int i = gapp.image->w*gapp.image->h; + int i = image_w*image_h; unsigned char *color = malloc(i*4); if (color) { - unsigned char *s = gapp.image->samples; + unsigned char *s = image_samples; unsigned char *d = color; for (; i > 0 ; i--) { @@ -387,9 +389,9 @@ static void winblit(pdfapp_t *app) x0, y0, color, 0, 0, - gapp.image->w, - gapp.image->h, - gapp.image->w * 4); + image_w, + image_h, + image_w * 4); free(color); } } @@ -462,7 +464,7 @@ void windocopy(pdfapp_t *app) { ucs = ucs2[0]; - utf8 += runetochar(utf8, &ucs); + utf8 += fz_runetochar(utf8, ucs); if (ucs < 256) *latin1++ = ucs; diff --git a/cbz/mucbz.c b/cbz/mucbz.c index 83c463bd..08f21bb6 100644 --- a/cbz/mucbz.c +++ b/cbz/mucbz.c @@ -1,4 +1,4 @@ -#include "fitz.h" +#include "fitz-internal.h" #include "mucbz.h" #include <zlib.h> @@ -19,9 +19,18 @@ static const char *cbz_ext_list[] = { NULL }; +typedef struct cbz_image_s cbz_image; + +struct cbz_image_s +{ + fz_image base; + int xres, yres; + fz_pixmap *pix; +}; + struct cbz_page_s { - fz_pixmap *image; + cbz_image *image; }; typedef struct cbz_entry_s cbz_entry; @@ -343,12 +352,34 @@ cbz_count_pages(cbz_document *doc) return doc->page_count; } +static void +cbz_free_image(fz_context *ctx, fz_storable *image_) +{ + cbz_image *image = (cbz_image *)image_; + + if (image == NULL) + return; + fz_drop_pixmap(ctx, image->pix); + fz_free(ctx, image); +} + +static fz_pixmap * +cbz_image_to_pixmap(fz_context *ctx, fz_image *image_, int x, int w) +{ + cbz_image *image = (cbz_image *)image_; + + return fz_keep_pixmap(ctx, image->pix); +} + + cbz_page * cbz_load_page(cbz_document *doc, int number) { fz_context *ctx = doc->ctx; unsigned char *data = NULL; cbz_page *page = NULL; + cbz_image *image = NULL; + fz_pixmap *pixmap = NULL; int size; if (number < 0 || number >= doc->page_count) @@ -358,19 +389,31 @@ cbz_load_page(cbz_document *doc, int number) fz_var(data); fz_var(page); + fz_var(image); + fz_var(pixmap); fz_try(ctx) { - page = fz_malloc_struct(doc->ctx, cbz_page); + page = fz_malloc_struct(ctx, cbz_page); page->image = NULL; data = cbz_read_zip_entry(doc, doc->entry[number].offset, &size); if (data[0] == 0xff && data[1] == 0xd8) - page->image = fz_load_jpeg(ctx, data, size); + pixmap = fz_load_jpeg(ctx, data, size); else if (memcmp(data, "\211PNG\r\n\032\n", 8) == 0) - page->image = fz_load_png(ctx, data, size); + pixmap = fz_load_png(ctx, data, size); else fz_throw(ctx, "unknown image format"); + + image = fz_malloc_struct(ctx, cbz_image); + FZ_INIT_STORABLE(&image->base, 1, cbz_free_image); + image->base.w = pixmap->w; + image->base.h = pixmap->h; + image->base.get_pixmap = cbz_image_to_pixmap; + image->xres = pixmap->xres; + image->yres = pixmap->yres; + image->pix = pixmap; + page->image = image; } fz_always(ctx) { @@ -378,9 +421,7 @@ cbz_load_page(cbz_document *doc, int number) } fz_catch(ctx) { - if (page && page->image) - fz_drop_pixmap(ctx, page->image); - fz_free(ctx, page); + cbz_free_page(doc, page); fz_rethrow(ctx); } @@ -390,29 +431,31 @@ cbz_load_page(cbz_document *doc, int number) void cbz_free_page(cbz_document *doc, cbz_page *page) { - fz_drop_pixmap(doc->ctx, page->image); + if (!page) + return; + fz_drop_image(doc->ctx, &page->image->base); fz_free(doc->ctx, page); } fz_rect cbz_bound_page(cbz_document *doc, cbz_page *page) { - fz_pixmap *image = page->image; + cbz_image *image = page->image; fz_rect bbox; bbox.x0 = bbox.y0 = 0; - bbox.x1 = image->w * DPI / image->xres; - bbox.y1 = image->h * DPI / image->yres; + bbox.x1 = image->base.w * DPI / image->xres; + bbox.y1 = image->base.h * DPI / image->yres; return bbox; } void cbz_run_page(cbz_document *doc, cbz_page *page, fz_device *dev, fz_matrix ctm, fz_cookie *cookie) { - fz_pixmap *image = page->image; - float w = image->w * DPI / image->xres; - float h = image->h * DPI / image->yres; + cbz_image *image = page->image; + float w = image->base.w * DPI / image->xres; + float h = image->base.h * DPI / image->yres; ctm = fz_concat(fz_scale(w, h), ctm); - fz_fill_image(dev, image, ctm, 1); + fz_fill_image(dev, &image->base, ctm, 1); } /* Document interface wrappers */ diff --git a/cbz/mucbz.h b/cbz/mucbz.h index e18a7474..080423bf 100644 --- a/cbz/mucbz.h +++ b/cbz/mucbz.h @@ -1,15 +1,45 @@ -#ifndef _MUCBZ_H_ -#define _MUCBZ_H_ +#ifndef MUCBZ_H +#define MUCBZ_H -#ifndef _FITZ_H_ -#error "fitz.h must be included before mucbz.h" -#endif +#include "fitz.h" typedef struct cbz_document_s cbz_document; typedef struct cbz_page_s cbz_page; +/* + cbz_open_document: Open a document. + + Open a document for reading so the library is able to locate + objects and pages inside the file. + + The returned cbz_document should be used when calling most + other functions. Note that it wraps the context, so those + functions implicitly get access to the global state in + context. + + filename: a path to a file as it would be given to open(2). +*/ cbz_document *cbz_open_document(fz_context *ctx, char *filename); + +/* + cbz_open_document_with_stream: Opens a document. + + Same as cbz_open_document, but takes a stream instead of a + filename to locate the document to open. Increments the + reference count of the stream. See fz_open_file, + fz_open_file_w or fz_open_fd for opening a stream, and + fz_close for closing an open stream. +*/ cbz_document *cbz_open_document_with_stream(fz_stream *file); + +/* + cbz_close_document: Closes and frees an opened document. + + The resource store in the context associated with cbz_document + is emptied. + + Does not throw exceptions. +*/ void cbz_close_document(cbz_document *doc); int cbz_count_pages(cbz_document *doc); diff --git a/doc/example.c b/doc/example.c new file mode 100644 index 00000000..31bf68b8 --- /dev/null +++ b/doc/example.c @@ -0,0 +1,100 @@ +// Rendering a page of a PDF document to a PNG image in less than 100 lines. + +// Compile a debug build of mupdf, then compile and run this example: +// +// gcc -o build/debug/example -I fitz doc/example.c \ +// build/debug/libfitz.a build/debug/libfreetype.a -lpng -ljpeg \ +// -ljbig2dec -lopenjpeg -lm +// +// build/debug/example /path/to/document.pdf 1 200 25 + +// Include MuPDF header files. The order is important! + +#include <fitz.h> + +void +render(char *filename, int pagenumber, int zoom, int rotation) +{ + // Create a context to hold the exception stack and various caches. + + fz_context *ctx = fz_new_context(NULL, NULL, FZ_STORE_UNLIMITED); + + // Open the PDF, XPS or CBZ document. + + fz_document *doc = fz_open_document(ctx, filename); + + // Retrieve the number of pages (not used in this example). + + int pagecount = fz_count_pages(doc); + + // Load the page we want. Page numbering starts from zero. + + fz_page *page = fz_load_page(doc, pagenumber - 1); + + // Calculate a transform to use when rendering. This transform + // contains the scale and rotation. Convert zoom percentage to a + // scaling factor. Without scaling the resolution is 72 dpi. + + fz_matrix transform = fz_scale(zoom / 100.0f, zoom / 100.0f); + transform = fz_concat(transform, fz_rotate(rotation)); + + // Take the page bounds and transform them by the same matrix that + // we will use to render the page. + + fz_rect rect = fz_bound_page(doc, page); + rect = fz_transform_rect(transform, rect); + fz_bbox bbox = fz_round_rect(rect); + + // Create a blank pixmap to hold the result of rendering. The + // pixmap bounds used here are the same as the transformed page + // bounds, so it will contain the entire page. The page coordinate + // space has the origin at the top left corner and the x axis + // extends to the right and the y axis extends down. + + fz_pixmap *pix = fz_new_pixmap_with_bbox(ctx, fz_device_rgb, bbox); + fz_clear_pixmap_with_value(ctx, pix, 0xff); + + // A page consists of a series of objects (text, line art, images, + // gradients). These objects are passed to a device when the + // interpreter runs the page. There are several devices, used for + // different purposes: + // + // draw device -- renders objects to a target pixmap. + // + // text device -- extracts the text in reading order with styling + // information. This text can be used to provide text search. + // + // list device -- records the graphic objects in a list that can + // be played back through another device. This is useful if you + // need to run the same page through multiple devices, without + // the overhead of parsing the page each time. + + // Create a draw device with the pixmap as its target. + // Run the page with the transform. + + fz_device *dev = fz_new_draw_device(ctx, pix); + fz_run_page(doc, page, dev, transform, NULL); + fz_free_device(dev); + + // Save the pixmap to a file. + + fz_write_png(ctx, pix, "out.png", 0); + + // Clean up. + + fz_drop_pixmap(ctx, pix); + fz_free_page(doc, page); + fz_close_document(doc); + fz_free_context(ctx); +} + +int main(int argc, char **argv) +{ + char *filename = argv[1]; + int pagenumber = argc > 2 ? atoi(argv[2]) : 1; + int zoom = argc > 3 ? atoi(argv[3]) : 100; + int rotation = argc > 4 ? atoi(argv[4]) : 0; + + render(filename, pagenumber, zoom, rotation); + return 0; +} diff --git a/doc/overview.txt b/doc/overview.txt new file mode 100644 index 00000000..25cd0d4b --- /dev/null +++ b/doc/overview.txt @@ -0,0 +1,212 @@ +Contents +======== + +* Basic MuPDF usage example +* Common function arguments +* Error Handling +* Multi-threading + +Basic MuPDF usage example +========================= + +For an example of how to use MuPDF in the most basic way, see +doc/example.c. To limit the complexity and give an easier introduction +this code has no error handling at all, but any serious piece of code +using MuPDF should use the error handling strategies described below. + +Common function arguments +========================= + +Many functions in MuPDFs interface take a context argument. + +A context contains global state used by MuPDF inside functions when +parsing or rendering pages of the document. It contains for example: + + an exception stack (see error handling below), + + a memory allocator (allowing for custom allocators) + + a resource store (for caching of images, fonts, etc.) + + a set of locks and (un-)locking functions (for multi-threading) + +Other functions in MuPDF's interface take arguments such as document, +stream and device which contain state for each type of object. Those +arguments each have a reference to a context and therefore act as +proxies for a context. + +Without the set of locks and accompanying functions the context and +its proxies may only be used in a single-threaded application. + +Error handling +============== + +MuPDF uses a set of exception handling macros to simplify error return +and cleanup. Conceptually, they work a lot like C++'s try/catch +system, but do not require any special compiler support. + +The basic formulation is as follows: + + fz_try(ctx) + { + // Try to perform a task. Never 'return', 'goto' or + // 'longjmp' out of here. 'break' may be used to + // safely exit (just) the try block scope. + } + fz_always(ctx) + { + // Any code here is always executed, regardless of + // whether an exception was thrown within the try or + // not. Never 'return', 'goto' or longjmp out from + // here. 'break' may be used to safely exit (just) the + // always block scope. + } + fz_catch(ctx) + { + // This code is called (after any always block) only + // if something within the fz_try block (including any + // functions it called) threw an exception. The code + // here is expected to handle the exception (maybe + // record/report the error, cleanup any stray state + // etc) and can then either exit the block, or pass on + // the exception to a higher level (enclosing) fz_try + // block (using fz_throw, or fz_rethrow). + } + +The fz_always block is optional, and can safely be omitted. + +The macro based nature of this system has 3 main limitations: + +1) Never return from within try (or 'goto' or longjmp out of it). + This upsets the internal housekeeping of the macros and will + cause problems later on. The code will detect such things + happening, but by then it is too late to give a helpful error + report as to where the original infraction occurred. + +2) The fz_try(ctx) { ... } fz_always(ctx) { ... } fz_catch(ctx) { ... } + is not one atomic C statement. That is to say, if you do: + + if (condition) + fz_try(ctx) { ... } + fz_catch(ctx) { ... } + + then you will not get what you want. Use the following instead: + + if (condition) { + fz_try(ctx) { ... } + fz_catch(ctx) { ... } + } + +3) The macros are implemented using setjmp and longjmp, and so + the standard C restrictions on the use of those functions + apply to fz_try/fz_catch too. In particular, any "truly local" + variable that is set between the start of fz_try and something + in fz_try throwing an exception may become undefined as part + of the process of throwing that exception. + + As a way of mitigating this problem, we provide an fz_var() + macro that tells the compiler to ensure that that variable is + not unset by the act of throwing the exception. + +A model piece of code using these macros then might be: + + house build_house(plans *p) + { + material m = NULL; + walls w = NULL; + roof r = NULL; + house h = NULL; + tiles t = make_tiles(); + + fz_var(w); + fz_var(r); + fz_var(h); + + fz_try(ctx) + { + fz_try(ctx) + { + m = make_bricks(); + } + fz_catch(ctx) + { + // No bricks available, make do with straw? + m = make_straw(); + } + w = make_walls(m, p); + r = make_roof(m, t); + // Note, NOT: return combine(w,r); + h = combine(w, r); + } + fz_always(ctx) + { + drop_walls(w); + drop_roof(r); + drop_material(m); + drop_tiles(t); + } + fz_catch(ctx) + { + fz_throw(ctx, "build_house failed"); + } + return h; + } + +Things to note about this: + +a) If make_tiles throws an exception, this will immediately be + handled by some higher level exception handler. If it + succeeds, t will be set before fz_try starts, so there is no + need to fz_var(t); + +b) We try first off to make some bricks as our building material. + If this fails, we fall back to straw. If this fails, we'll end + up in the fz_catch, and the process will fail neatly. + +c) We assume in this code that combine takes new reference to + both the walls and the roof it uses, and therefore that w and + r need to be cleaned up in all cases. + +d) We assume the standard C convention that it is safe to destroy + NULL things. + +Multi-threading +=============== + +First off, study the basic usage example in doc/example.c and make +sure you understand how it works as it will be the referenced in this +section too. + +There are two variations of how to create multi-threaded applications: + +1) lock-less operation -- in which one thread is requesting pages + to be drawn and responding to user interface actions, while + another thread is dedicated to drawing pages. In this scenario + only one thread owns and manipulates the context and document + at any one time. + +2) using locking -- where one thread is requesting pages to be + draw and responding to user interface actions, while several + threads may be drawing pages. In this scenario each thread has + its own context but they share some global state, for example + the resource store. An additional constraint + +The usage example starts by getting a context from fz_new_context with +standard memory allocation functions, default resource store size and, +crucially, no locking. + +In a multi-threaded application every thread must have a context. Or +more specifically, each context can only be used from one thread at a +time. When starting another thread, do NOT call fz_new_context again; +instead call fz_clone_context. This creates a context sharing the +memory allocator, resource store etc. + + + + +så utan lås: en gui-tråd som visa progress, en tråd som renderar +med lås: en gui-tråd som request:ar och flera trådar som renderar + +having fitz level display list objects created in +one thread, consumed as read-only in multiple threads, with locked access +around a few shared caches diff --git a/draw/draw_affine.c b/draw/draw_affine.c index dc15eaf5..67361faf 100644 --- a/draw/draw_affine.c +++ b/draw/draw_affine.c @@ -1,4 +1,4 @@ -#include "fitz.h" +#include "fitz-internal.h" typedef unsigned char byte; diff --git a/draw/draw_blend.c b/draw/draw_blend.c index e60c09c5..7c74df79 100644 --- a/draw/draw_blend.c +++ b/draw/draw_blend.c @@ -1,4 +1,4 @@ -#include "fitz.h" +#include "fitz-internal.h" /* PDF 1.4 blend modes. These are slow. */ @@ -24,7 +24,7 @@ static const char *fz_blendmode_names[] = "Luminosity", }; -int fz_find_blendmode(char *name) +int fz_lookup_blendmode(char *name) { int i; for (i = 0; i < nelem(fz_blendmode_names); i++) @@ -589,8 +589,8 @@ fz_blend_pixmap(fz_pixmap *dst, fz_pixmap *src, int alpha, int blendmode, int is } } - bbox = fz_bound_pixmap(dst); - bbox = fz_intersect_bbox(bbox, fz_bound_pixmap(src)); + bbox = fz_pixmap_bbox_no_ctx(dst); + bbox = fz_intersect_bbox(bbox, fz_pixmap_bbox_no_ctx(src)); x = bbox.x0; y = bbox.y0; diff --git a/draw/draw_device.c b/draw/draw_device.c index 279ef64d..76f934bd 100644 --- a/draw/draw_device.c +++ b/draw/draw_device.c @@ -1,4 +1,4 @@ -#include "fitz.h" +#include "fitz-internal.h" #define QUANT(x,a) (((int)((x) * (a))) / (a)) #define HSUBPIX 5.0 @@ -121,9 +121,9 @@ fz_knockout_begin(fz_draw_device *dev) state = push_stack(dev); - bbox = fz_bound_pixmap(state->dest); + bbox = fz_pixmap_bbox(dev->ctx, state->dest); bbox = fz_intersect_bbox(bbox, state->scissor); - dest = fz_new_pixmap_with_rect(dev->ctx, state->dest->colorspace, bbox); + dest = fz_new_pixmap_with_bbox(dev->ctx, state->dest->colorspace, bbox); if (isolated) { @@ -154,7 +154,7 @@ fz_knockout_begin(fz_draw_device *dev) } else { - shape = fz_new_pixmap_with_rect(dev->ctx, NULL, bbox); + shape = fz_new_pixmap_with_bbox(dev->ctx, NULL, bbox); fz_clear_pixmap(dev->ctx, shape); } #ifdef DUMP_GROUP_BLENDS @@ -248,7 +248,7 @@ fz_draw_fill_path(fz_device *devp, fz_path *path, int even_odd, fz_matrix ctm, if (state->blendmode & FZ_BLEND_KNOCKOUT) state = fz_knockout_begin(dev); - fz_convert_color(dev->ctx, colorspace, color, model, colorfv); + fz_convert_color(dev->ctx, model, colorfv, colorspace, color); for (i = 0; i < model->n; i++) colorbv[i] = colorfv[i] * 255; colorbv[i] = alpha * 255; @@ -302,7 +302,7 @@ fz_draw_stroke_path(fz_device *devp, fz_path *path, fz_stroke_state *stroke, fz_ if (state->blendmode & FZ_BLEND_KNOCKOUT) state = fz_knockout_begin(dev); - fz_convert_color(dev->ctx, colorspace, color, model, colorfv); + fz_convert_color(dev->ctx, model, colorfv, colorspace, color); for (i = 0; i < model->n; i++) colorbv[i] = colorfv[i] * 255; colorbv[i] = alpha * 255; @@ -354,13 +354,13 @@ fz_draw_clip_path(fz_device *devp, fz_path *path, fz_rect *rect, int even_odd, f return; } - state[1].mask = fz_new_pixmap_with_rect(dev->ctx, NULL, bbox); + state[1].mask = fz_new_pixmap_with_bbox(dev->ctx, NULL, bbox); fz_clear_pixmap(dev->ctx, state[1].mask); - state[1].dest = fz_new_pixmap_with_rect(dev->ctx, model, bbox); + state[1].dest = fz_new_pixmap_with_bbox(dev->ctx, model, bbox); fz_clear_pixmap(dev->ctx, state[1].dest); if (state[1].shape) { - state[1].shape = fz_new_pixmap_with_rect(dev->ctx, NULL, bbox); + state[1].shape = fz_new_pixmap_with_bbox(dev->ctx, NULL, bbox); fz_clear_pixmap(dev->ctx, state[1].shape); } @@ -399,13 +399,13 @@ fz_draw_clip_stroke_path(fz_device *devp, fz_path *path, fz_rect *rect, fz_strok if (rect) bbox = fz_intersect_bbox(bbox, fz_round_rect(*rect)); - state[1].mask = fz_new_pixmap_with_rect(dev->ctx, NULL, bbox); + state[1].mask = fz_new_pixmap_with_bbox(dev->ctx, NULL, bbox); fz_clear_pixmap(dev->ctx, state[1].mask); - state[1].dest = fz_new_pixmap_with_rect(dev->ctx, model, bbox); + state[1].dest = fz_new_pixmap_with_bbox(dev->ctx, model, bbox); fz_clear_pixmap(dev->ctx, state[1].dest); if (state->shape) { - state[1].shape = fz_new_pixmap_with_rect(dev->ctx, NULL, bbox); + state[1].shape = fz_new_pixmap_with_bbox(dev->ctx, NULL, bbox); fz_clear_pixmap(dev->ctx, state[1].shape); } @@ -427,7 +427,7 @@ draw_glyph(unsigned char *colorbv, fz_pixmap *dst, fz_pixmap *msk, fz_bbox bbox; int x, y, w, h; - bbox = fz_bound_pixmap(msk); + bbox = fz_pixmap_bbox_no_ctx(msk); bbox.x0 += xorig; bbox.y0 += yorig; bbox.x1 += xorig; @@ -472,7 +472,7 @@ fz_draw_fill_text(fz_device *devp, fz_text *text, fz_matrix ctm, if (state->blendmode & FZ_BLEND_KNOCKOUT) state = fz_knockout_begin(dev); - fz_convert_color(dev->ctx, colorspace, color, model, colorfv); + fz_convert_color(dev->ctx, model, colorfv, colorspace, color); for (i = 0; i < model->n; i++) colorbv[i] = colorfv[i] * 255; colorbv[i] = alpha * 255; @@ -532,7 +532,7 @@ fz_draw_stroke_text(fz_device *devp, fz_text *text, fz_stroke_state *stroke, fz_ if (state->blendmode & FZ_BLEND_KNOCKOUT) state = fz_knockout_begin(dev); - fz_convert_color(dev->ctx, colorspace, color, model, colorfv); + fz_convert_color(dev->ctx, model, colorfv, colorspace, color); for (i = 0; i < model->n; i++) colorbv[i] = colorfv[i] * 255; colorbv[i] = alpha * 255; @@ -600,13 +600,13 @@ fz_draw_clip_text(fz_device *devp, fz_text *text, fz_matrix ctm, int accumulate) if (accumulate == 0 || accumulate == 1) { - mask = fz_new_pixmap_with_rect(dev->ctx, NULL, bbox); + mask = fz_new_pixmap_with_bbox(dev->ctx, NULL, bbox); fz_clear_pixmap(dev->ctx, mask); - dest = fz_new_pixmap_with_rect(dev->ctx, model, bbox); + dest = fz_new_pixmap_with_bbox(dev->ctx, model, bbox); fz_clear_pixmap(dev->ctx, dest); if (state->shape) { - shape = fz_new_pixmap_with_rect(dev->ctx, NULL, bbox); + shape = fz_new_pixmap_with_bbox(dev->ctx, NULL, bbox); fz_clear_pixmap(dev->ctx, shape); } else @@ -673,13 +673,13 @@ fz_draw_clip_stroke_text(fz_device *devp, fz_text *text, fz_stroke_state *stroke bbox = fz_round_rect(fz_bound_text(dev->ctx, text, ctm)); bbox = fz_intersect_bbox(bbox, state->scissor); - mask = fz_new_pixmap_with_rect(dev->ctx, NULL, bbox); + mask = fz_new_pixmap_with_bbox(dev->ctx, NULL, bbox); fz_clear_pixmap(dev->ctx, mask); - dest = fz_new_pixmap_with_rect(dev->ctx, model, bbox); + dest = fz_new_pixmap_with_bbox(dev->ctx, model, bbox); fz_clear_pixmap(dev->ctx, dest); if (state->shape) { - shape = fz_new_pixmap_with_rect(dev->ctx, NULL, bbox); + shape = fz_new_pixmap_with_bbox(dev->ctx, NULL, bbox); fz_clear_pixmap(dev->ctx, shape); } else @@ -762,11 +762,11 @@ fz_draw_fill_shade(fz_device *devp, fz_shade *shade, fz_matrix ctm, float alpha) if (alpha < 1) { - dest = fz_new_pixmap_with_rect(dev->ctx, state->dest->colorspace, bbox); + dest = fz_new_pixmap_with_bbox(dev->ctx, state->dest->colorspace, bbox); fz_clear_pixmap(dev->ctx, dest); if (shape) { - shape = fz_new_pixmap_with_rect(dev->ctx, NULL, bbox); + shape = fz_new_pixmap_with_bbox(dev->ctx, NULL, bbox); fz_clear_pixmap(dev->ctx, shape); } } @@ -775,7 +775,7 @@ fz_draw_fill_shade(fz_device *devp, fz_shade *shade, fz_matrix ctm, float alpha) { unsigned char *s; int x, y, n, i; - fz_convert_color(dev->ctx, shade->colorspace, shade->background, model, colorfv); + fz_convert_color(dev->ctx, model, colorfv, shade->colorspace, shade->background); for (i = 0; i < model->n; i++) colorbv[i] = colorfv[i] * 255; colorbv[i] = 255; @@ -878,17 +878,19 @@ fz_transform_pixmap(fz_context *ctx, fz_pixmap *image, fz_matrix *ctm, int x, in } static void -fz_draw_fill_image(fz_device *devp, fz_pixmap *image, fz_matrix ctm, float alpha) +fz_draw_fill_image(fz_device *devp, fz_image *image, fz_matrix ctm, float alpha) { fz_draw_device *dev = devp->user; fz_pixmap *converted = NULL; fz_pixmap *scaled = NULL; + fz_pixmap *pixmap; + fz_pixmap *orig_pixmap; int after; int dx, dy; fz_context *ctx = dev->ctx; fz_draw_state *state = &dev->stack[dev->top]; fz_colorspace *model = state->dest->colorspace; - fz_bbox clip = fz_bound_pixmap(state->dest); + fz_bbox clip = fz_pixmap_bbox(ctx, state->dest); clip = fz_intersect_bbox(clip, state->scissor); @@ -903,133 +905,153 @@ fz_draw_fill_image(fz_device *devp, fz_pixmap *image, fz_matrix ctm, float alpha if (image->w == 0 || image->h == 0) return; + dx = sqrtf(ctm.a * ctm.a + ctm.b * ctm.b); + dy = sqrtf(ctm.c * ctm.c + ctm.d * ctm.d); + + pixmap = fz_image_to_pixmap(ctx, image, dx, dy); + orig_pixmap = pixmap; + /* convert images with more components (cmyk->rgb) before scaling */ /* convert images with fewer components (gray->rgb after scaling */ /* convert images with expensive colorspace transforms after scaling */ - if (state->blendmode & FZ_BLEND_KNOCKOUT) - state = fz_knockout_begin(dev); + fz_try(ctx) + { + if (state->blendmode & FZ_BLEND_KNOCKOUT) + state = fz_knockout_begin(dev); - after = 0; - if (image->colorspace == fz_device_gray) - after = 1; + after = 0; + if (pixmap->colorspace == fz_device_gray) + after = 1; - if (image->colorspace != model && !after) - { - converted = fz_new_pixmap_with_rect(ctx, model, fz_bound_pixmap(image)); - fz_convert_pixmap(ctx, image, converted); - image = converted; - } + if (pixmap->colorspace != model && !after) + { + converted = fz_new_pixmap_with_bbox(ctx, model, fz_pixmap_bbox(ctx, pixmap)); + fz_convert_pixmap(ctx, converted, pixmap); + pixmap = converted; + } - fz_try(ctx) - { - dx = sqrtf(ctm.a * ctm.a + ctm.b * ctm.b); - dy = sqrtf(ctm.c * ctm.c + ctm.d * ctm.d); - if (dx < image->w && dy < image->h) + if (dx < pixmap->w && dy < pixmap->h) { int gridfit = alpha == 1.0f && !(dev->flags & FZ_DRAWDEV_FLAGS_TYPE3); - scaled = fz_transform_pixmap(ctx, image, &ctm, state->dest->x, state->dest->y, dx, dy, gridfit, &clip); + scaled = fz_transform_pixmap(ctx, pixmap, &ctm, state->dest->x, state->dest->y, dx, dy, gridfit, &clip); if (!scaled) { if (dx < 1) dx = 1; if (dy < 1) dy = 1; - scaled = fz_scale_pixmap(ctx, image, image->x, image->y, dx, dy, NULL); + scaled = fz_scale_pixmap(ctx, pixmap, pixmap->x, pixmap->y, dx, dy, NULL); } if (scaled) - image = scaled; + pixmap = scaled; } - if (image->colorspace != model) + if (pixmap->colorspace != model) { - if ((image->colorspace == fz_device_gray && model == fz_device_rgb) || - (image->colorspace == fz_device_gray && model == fz_device_bgr)) + if ((pixmap->colorspace == fz_device_gray && model == fz_device_rgb) || + (pixmap->colorspace == fz_device_gray && model == fz_device_bgr)) { /* We have special case rendering code for gray -> rgb/bgr */ } else { - converted = fz_new_pixmap_with_rect(ctx, model, fz_bound_pixmap(image)); - fz_convert_pixmap(ctx, image, converted); - image = converted; + converted = fz_new_pixmap_with_bbox(ctx, model, fz_pixmap_bbox(ctx, pixmap)); + fz_convert_pixmap(ctx, converted, pixmap); + pixmap = converted; } } - fz_paint_image(state->dest, state->scissor, state->shape, image, ctm, alpha * 255); + fz_paint_image(state->dest, state->scissor, state->shape, pixmap, ctm, alpha * 255); + + if (state->blendmode & FZ_BLEND_KNOCKOUT) + fz_knockout_end(dev); } - fz_catch(ctx) + fz_always(ctx) { fz_drop_pixmap(ctx, scaled); fz_drop_pixmap(ctx, converted); + fz_drop_pixmap(ctx, orig_pixmap); + } + fz_catch(ctx) + { fz_rethrow(ctx); } - - if (scaled) - fz_drop_pixmap(ctx, scaled); - if (converted) - fz_drop_pixmap(ctx, converted); - - if (state->blendmode & FZ_BLEND_KNOCKOUT) - fz_knockout_end(dev); } static void -fz_draw_fill_image_mask(fz_device *devp, fz_pixmap *image, fz_matrix ctm, +fz_draw_fill_image_mask(fz_device *devp, fz_image *image, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha) { fz_draw_device *dev = devp->user; unsigned char colorbv[FZ_MAX_COLORS + 1]; float colorfv[FZ_MAX_COLORS]; fz_pixmap *scaled = NULL; + fz_pixmap *pixmap; + fz_pixmap *orig_pixmap; int dx, dy; int i; + fz_context *ctx = dev->ctx; fz_draw_state *state = &dev->stack[dev->top]; fz_colorspace *model = state->dest->colorspace; - fz_bbox clip = fz_bound_pixmap(state->dest); + fz_bbox clip = fz_pixmap_bbox(ctx, state->dest); clip = fz_intersect_bbox(clip, state->scissor); if (image->w == 0 || image->h == 0) return; - if (state->blendmode & FZ_BLEND_KNOCKOUT) - state = fz_knockout_begin(dev); - dx = sqrtf(ctm.a * ctm.a + ctm.b * ctm.b); dy = sqrtf(ctm.c * ctm.c + ctm.d * ctm.d); - if (dx < image->w && dy < image->h) + pixmap = fz_image_to_pixmap(ctx, image, dx, dy); + orig_pixmap = pixmap; + + fz_try(ctx) { - int gridfit = alpha == 1.0f && !(dev->flags & FZ_DRAWDEV_FLAGS_TYPE3); - scaled = fz_transform_pixmap(dev->ctx, image, &ctm, state->dest->x, state->dest->y, dx, dy, gridfit, &clip); - if (!scaled) + if (state->blendmode & FZ_BLEND_KNOCKOUT) + state = fz_knockout_begin(dev); + + if (dx < pixmap->w && dy < pixmap->h) { - if (dx < 1) - dx = 1; - if (dy < 1) - dy = 1; - scaled = fz_scale_pixmap(dev->ctx, image, image->x, image->y, dx, dy, NULL); + int gridfit = alpha == 1.0f && !(dev->flags & FZ_DRAWDEV_FLAGS_TYPE3); + scaled = fz_transform_pixmap(dev->ctx, pixmap, &ctm, state->dest->x, state->dest->y, dx, dy, gridfit, &clip); + if (!scaled) + { + if (dx < 1) + dx = 1; + if (dy < 1) + dy = 1; + scaled = fz_scale_pixmap(dev->ctx, pixmap, pixmap->x, pixmap->y, dx, dy, NULL); + } + if (scaled) + pixmap = scaled; } - if (scaled) - image = scaled; - } - fz_convert_color(dev->ctx, colorspace, color, model, colorfv); - for (i = 0; i < model->n; i++) - colorbv[i] = colorfv[i] * 255; - colorbv[i] = alpha * 255; + fz_convert_color(dev->ctx, model, colorfv, colorspace, color); + for (i = 0; i < model->n; i++) + colorbv[i] = colorfv[i] * 255; + colorbv[i] = alpha * 255; - fz_paint_image_with_color(state->dest, state->scissor, state->shape, image, ctm, colorbv); + fz_paint_image_with_color(state->dest, state->scissor, state->shape, pixmap, ctm, colorbv); - if (scaled) - fz_drop_pixmap(dev->ctx, scaled); + if (scaled) + fz_drop_pixmap(dev->ctx, scaled); - if (state->blendmode & FZ_BLEND_KNOCKOUT) - fz_knockout_end(dev); + if (state->blendmode & FZ_BLEND_KNOCKOUT) + fz_knockout_end(dev); + } + fz_always(ctx) + { + fz_drop_pixmap(dev->ctx, orig_pixmap); + } + fz_catch(ctx) + { + fz_rethrow(ctx); + } } static void -fz_draw_clip_image_mask(fz_device *devp, fz_pixmap *image, fz_rect *rect, fz_matrix ctm) +fz_draw_clip_image_mask(fz_device *devp, fz_image *image, fz_rect *rect, fz_matrix ctm) { fz_draw_device *dev = devp->user; fz_context *ctx = dev->ctx; @@ -1038,10 +1060,12 @@ fz_draw_clip_image_mask(fz_device *devp, fz_pixmap *image, fz_rect *rect, fz_mat fz_pixmap *dest = NULL; fz_pixmap *shape = NULL; fz_pixmap *scaled = NULL; + fz_pixmap *pixmap; + fz_pixmap *orig_pixmap; int dx, dy; fz_draw_state *state = push_stack(dev); fz_colorspace *model = state->dest->colorspace; - fz_bbox clip = fz_bound_pixmap(state->dest); + fz_bbox clip = fz_pixmap_bbox(ctx, state->dest); clip = fz_intersect_bbox(clip, state->scissor); @@ -1068,35 +1092,46 @@ fz_draw_clip_image_mask(fz_device *devp, fz_pixmap *image, fz_rect *rect, fz_mat if (rect) bbox = fz_intersect_bbox(bbox, fz_round_rect(*rect)); - mask = fz_new_pixmap_with_rect(dev->ctx, NULL, bbox); - fz_clear_pixmap(dev->ctx, mask); + dx = sqrtf(ctm.a * ctm.a + ctm.b * ctm.b); + dy = sqrtf(ctm.c * ctm.c + ctm.d * ctm.d); + pixmap = fz_image_to_pixmap(ctx, image, dx, dy); + orig_pixmap = pixmap; + fz_try(ctx) { - dest = fz_new_pixmap_with_rect(dev->ctx, model, bbox); + mask = fz_new_pixmap_with_bbox(dev->ctx, NULL, bbox); + fz_clear_pixmap(dev->ctx, mask); + + dest = fz_new_pixmap_with_bbox(dev->ctx, model, bbox); fz_clear_pixmap(dev->ctx, dest); if (state->shape) { - shape = fz_new_pixmap_with_rect(dev->ctx, NULL, bbox); + shape = fz_new_pixmap_with_bbox(dev->ctx, NULL, bbox); fz_clear_pixmap(dev->ctx, shape); } - dx = sqrtf(ctm.a * ctm.a + ctm.b * ctm.b); - dy = sqrtf(ctm.c * ctm.c + ctm.d * ctm.d); - if (dx < image->w && dy < image->h) + if (dx < pixmap->w && dy < pixmap->h) { int gridfit = !(dev->flags & FZ_DRAWDEV_FLAGS_TYPE3); - scaled = fz_transform_pixmap(dev->ctx, image, &ctm, state->dest->x, state->dest->y, dx, dy, gridfit, &clip); + scaled = fz_transform_pixmap(dev->ctx, pixmap, &ctm, state->dest->x, state->dest->y, dx, dy, gridfit, &clip); if (!scaled) { if (dx < 1) dx = 1; if (dy < 1) dy = 1; - scaled = fz_scale_pixmap(dev->ctx, image, image->x, image->y, dx, dy, NULL); + scaled = fz_scale_pixmap(dev->ctx, pixmap, pixmap->x, pixmap->y, dx, dy, NULL); } if (scaled) - image = scaled; + pixmap = scaled; } + fz_paint_image(mask, bbox, state->shape, pixmap, ctm, 255); + + } + fz_always(ctx) + { + fz_drop_pixmap(ctx, scaled); + fz_drop_pixmap(ctx, orig_pixmap); } fz_catch(ctx) { @@ -1106,11 +1141,6 @@ fz_draw_clip_image_mask(fz_device *devp, fz_pixmap *image, fz_rect *rect, fz_mat fz_rethrow(ctx); } - fz_paint_image(mask, bbox, state->shape, image, ctm, 255); - - if (scaled) - fz_drop_pixmap(dev->ctx, scaled); - state[1].blendmode |= FZ_BLEND_ISOLATED; state[1].scissor = bbox; state[1].dest = dest; @@ -1181,12 +1211,12 @@ fz_draw_begin_mask(fz_device *devp, fz_rect rect, int luminosity, fz_colorspace bbox = fz_round_rect(rect); bbox = fz_intersect_bbox(bbox, state->scissor); - dest = fz_new_pixmap_with_rect(dev->ctx, fz_device_gray, bbox); + dest = fz_new_pixmap_with_bbox(dev->ctx, fz_device_gray, bbox); if (state->shape) { /* FIXME: If we ever want to support AIS true, then we * probably want to create a shape pixmap here, using: - * shape = fz_new_pixmap_with_rect(NULL, bbox); + * shape = fz_new_pixmap_with_bbox(NULL, bbox); * then, in the end_mask code, we create the mask from this * rather than dest. */ @@ -1198,7 +1228,7 @@ fz_draw_begin_mask(fz_device *devp, fz_rect rect, int luminosity, fz_colorspace float bc; if (!colorspace) colorspace = fz_device_gray; - fz_convert_color(dev->ctx, colorspace, colorfv, fz_device_gray, &bc); + fz_convert_color(dev->ctx, fz_device_gray, &bc, colorspace, colorfv); fz_clear_pixmap_with_value(dev->ctx, dest, bc * 255); if (shape) fz_clear_pixmap_with_value(dev->ctx, shape, 255); @@ -1254,8 +1284,8 @@ fz_draw_end_mask(fz_device *devp) state[1].mask = NULL; /* create new dest scratch buffer */ - bbox = fz_bound_pixmap(temp); - dest = fz_new_pixmap_with_rect(dev->ctx, state->dest->colorspace, bbox); + bbox = fz_pixmap_bbox(ctx, temp); + dest = fz_new_pixmap_with_bbox(dev->ctx, state->dest->colorspace, bbox); fz_clear_pixmap(dev->ctx, dest); /* push soft mask as clip mask */ @@ -1266,7 +1296,7 @@ fz_draw_end_mask(fz_device *devp) * clip mask when we pop. So create a new shape now. */ if (state[0].shape) { - state[1].shape = fz_new_pixmap_with_rect(dev->ctx, NULL, bbox); + state[1].shape = fz_new_pixmap_with_bbox(dev->ctx, NULL, bbox); fz_clear_pixmap(dev->ctx, state[1].shape); } state[1].scissor = bbox; @@ -1288,7 +1318,7 @@ fz_draw_begin_group(fz_device *devp, fz_rect rect, int isolated, int knockout, i state = push_stack(dev); bbox = fz_round_rect(rect); bbox = fz_intersect_bbox(bbox, state->scissor); - dest = fz_new_pixmap_with_rect(ctx, model, bbox); + dest = fz_new_pixmap_with_bbox(ctx, model, bbox); #ifndef ATTEMPT_KNOCKOUT_AND_ISOLATED knockout = 0; @@ -1314,7 +1344,7 @@ fz_draw_begin_group(fz_device *devp, fz_rect rect, int isolated, int knockout, i { fz_try(ctx) { - shape = fz_new_pixmap_with_rect(ctx, NULL, bbox); + shape = fz_new_pixmap_with_bbox(ctx, NULL, bbox); fz_clear_pixmap(dev->ctx, shape); } fz_catch(ctx) @@ -1421,7 +1451,7 @@ fz_draw_begin_tile(fz_device *devp, fz_rect area, fz_rect view, float xstep, flo * assert(bbox.x0 > state->dest->x || bbox.x1 < state->dest->x + state->dest->w || * bbox.y0 > state->dest->y || bbox.y1 < state->dest->y + state->dest->h); */ - dest = fz_new_pixmap_with_rect(dev->ctx, model, bbox); + dest = fz_new_pixmap_with_bbox(dev->ctx, model, bbox); fz_clear_pixmap(ctx, dest); shape = state[0].shape; if (shape) @@ -1429,7 +1459,7 @@ fz_draw_begin_tile(fz_device *devp, fz_rect area, fz_rect view, float xstep, flo fz_var(shape); fz_try(ctx) { - shape = fz_new_pixmap_with_rect(dev->ctx, NULL, bbox); + shape = fz_new_pixmap_with_bbox(dev->ctx, NULL, bbox); fz_clear_pixmap(ctx, shape); } fz_catch(ctx) @@ -1552,9 +1582,6 @@ fz_draw_free_user(fz_device *devp) state--; } while(--dev->top > 0); - fz_drop_pixmap(ctx, dev->stack[0].mask); - fz_drop_pixmap(ctx, dev->stack[0].dest); - fz_drop_pixmap(ctx, dev->stack[0].shape); } if (dev->stack != &dev->init_stack[0]) fz_free(ctx, dev->stack); diff --git a/draw/draw_edge.c b/draw/draw_edge.c index adb460ac..12ba72fc 100644 --- a/draw/draw_edge.c +++ b/draw/draw_edge.c @@ -1,4 +1,4 @@ -#include "fitz.h" +#include "fitz-internal.h" #define BBOX_MIN -(1<<20) #define BBOX_MAX (1<<20) @@ -20,7 +20,7 @@ struct fz_aa_context_s int hscale; int vscale; int scale; - int level; + int bits; }; void fz_new_aa_context(fz_context *ctx) @@ -30,17 +30,23 @@ void fz_new_aa_context(fz_context *ctx) ctx->aa->hscale = 17; ctx->aa->vscale = 15; ctx->aa->scale = 256; - ctx->aa->level = 8; + ctx->aa->bits = 8; #define fz_aa_hscale ((ctxaa)->hscale) #define fz_aa_vscale ((ctxaa)->vscale) #define fz_aa_scale ((ctxaa)->scale) -#define fz_aa_level ((ctxaa)->level) +#define fz_aa_bits ((ctxaa)->bits) #define AA_SCALE(x) ((x * fz_aa_scale) >> 8) #endif } +void fz_copy_aa_context(fz_context *dst, fz_context *src) +{ + if (dst && dst->aa && src && src->aa) + memcpy(dst->aa, src->aa, sizeof(*src->aa)); +} + void fz_free_aa_context(fz_context *ctx) { #ifndef AA_BITS @@ -55,40 +61,40 @@ void fz_free_aa_context(fz_context *ctx) #define AA_SCALE(x) (x) #define fz_aa_hscale 17 #define fz_aa_vscale 15 -#define fz_aa_level 8 +#define fz_aa_bits 8 #elif AA_BITS > 4 #define AA_SCALE(x) ((x * 255) >> 6) #define fz_aa_hscale 8 #define fz_aa_vscale 8 -#define fz_aa_level 6 +#define fz_aa_bits 6 #elif AA_BITS > 2 #define AA_SCALE(x) (x * 17) #define fz_aa_hscale 5 #define fz_aa_vscale 3 -#define fz_aa_level 4 +#define fz_aa_bits 4 #elif AA_BITS > 0 #define AA_SCALE(x) ((x * 255) >> 2) #define fz_aa_hscale 2 #define fz_aa_vscale 2 -#define fz_aa_level 2 +#define fz_aa_bits 2 #else #define AA_SCALE(x) (x * 255) #define fz_aa_hscale 1 #define fz_aa_vscale 1 -#define fz_aa_level 0 +#define fz_aa_bits 0 #endif #endif int -fz_get_aa_level(fz_context *ctx) +fz_aa_level(fz_context *ctx) { fz_aa_context *ctxaa = ctx->aa; - return fz_aa_level; + return fz_aa_bits; } void @@ -96,37 +102,37 @@ fz_set_aa_level(fz_context *ctx, int level) { fz_aa_context *ctxaa = ctx->aa; #ifdef AA_BITS - fz_warn(ctx, "anti-aliasing was compiled with a fixed precision of %d bits", fz_aa_level); + fz_warn(ctx, "anti-aliasing was compiled with a fixed precision of %d bits", fz_aa_bits); #else if (level > 6) { fz_aa_hscale = 17; fz_aa_vscale = 15; - fz_aa_level = 8; + fz_aa_bits = 8; } else if (level > 4) { fz_aa_hscale = 8; fz_aa_vscale = 8; - fz_aa_level = 6; + fz_aa_bits = 6; } else if (level > 2) { fz_aa_hscale = 5; fz_aa_vscale = 3; - fz_aa_level = 4; + fz_aa_bits = 4; } else if (level > 0) { fz_aa_hscale = 2; fz_aa_vscale = 2; - fz_aa_level = 2; + fz_aa_bits = 2; } else { fz_aa_hscale = 1; fz_aa_vscale = 1; - fz_aa_level = 0; + fz_aa_bits = 0; } fz_aa_scale = 0xFF00 / (fz_aa_hscale * fz_aa_vscale); #endif @@ -792,7 +798,7 @@ fz_scan_convert(fz_gel *gel, int eofill, fz_bbox clip, { fz_aa_context *ctxaa = gel->ctx->aa; - if (fz_aa_level > 0) + if (fz_aa_bits > 0) fz_scan_convert_aa(gel, eofill, clip, dst, color); else fz_scan_convert_sharp(gel, eofill, clip, dst, color); diff --git a/draw/draw_glyph.c b/draw/draw_glyph.c index 68ae3b80..cef9d7fa 100644 --- a/draw/draw_glyph.c +++ b/draw/draw_glyph.c @@ -1,4 +1,4 @@ -#include "fitz.h" +#include "fitz-internal.h" #define MAX_FONT_SIZE 1000 #define MAX_GLYPH_SIZE 256 @@ -20,6 +20,7 @@ struct fz_glyph_key_s int c, d; unsigned short gid; unsigned char e, f; + int aa; }; void @@ -30,7 +31,7 @@ fz_new_glyph_cache_context(fz_context *ctx) cache = fz_malloc_struct(ctx, fz_glyph_cache); fz_try(ctx) { - cache->hash = fz_new_hash_table(ctx, 509, sizeof(fz_glyph_key)); + cache->hash = fz_new_hash_table(ctx, 509, sizeof(fz_glyph_key), FZ_LOCK_GLYPHCACHE); } fz_catch(ctx) { @@ -128,6 +129,7 @@ fz_render_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix ctm, fz_color key.d = ctm.d * 65536; key.e = (ctm.e - floorf(ctm.e)) * 256; key.f = (ctm.f - floorf(ctm.f)) * 256; + key.aa = fz_aa_level(ctx); fz_lock(ctx, FZ_LOCK_GLYPHCACHE); val = fz_hash_find(ctx, cache->hash, &key); @@ -145,7 +147,7 @@ fz_render_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix ctm, fz_color { if (font->ft_face) { - val = fz_render_ft_glyph(ctx, font, gid, ctm); + val = fz_render_ft_glyph(ctx, font, gid, ctm, key.aa); } else if (font->t3procs) { diff --git a/draw/draw_mesh.c b/draw/draw_mesh.c index 79bac732..7579ad60 100644 --- a/draw/draw_mesh.c +++ b/draw/draw_mesh.c @@ -1,4 +1,4 @@ -#include "fitz.h" +#include "fitz-internal.h" /* * polygon clipping @@ -509,7 +509,7 @@ fz_paint_mesh(fz_context *ctx, fz_shade *shade, fz_matrix ctm, fz_pixmap *dest, tri[k][2] = *mesh++ * 255; else { - fz_convert_color(ctx, shade->colorspace, mesh, dest->colorspace, tri[k] + 2); + fz_convert_color(ctx, dest->colorspace, tri[k] + 2, shade->colorspace, mesh); for (i = 0; i < dest->colorspace->n; i++) tri[k][i + 2] *= 255; mesh += shade->colorspace->n; @@ -539,13 +539,13 @@ fz_paint_shade(fz_context *ctx, fz_shade *shade, fz_matrix ctm, fz_pixmap *dest, { for (i = 0; i < 256; i++) { - fz_convert_color(ctx, shade->colorspace, shade->function[i], dest->colorspace, color); + fz_convert_color(ctx, dest->colorspace, color, shade->colorspace, shade->function[i]); for (k = 0; k < dest->colorspace->n; k++) clut[i][k] = color[k] * 255; clut[i][k] = shade->function[i][shade->colorspace->n] * 255; } - conv = fz_new_pixmap_with_rect(ctx, dest->colorspace, bbox); - temp = fz_new_pixmap_with_rect(ctx, fz_device_gray, bbox); + conv = fz_new_pixmap_with_bbox(ctx, dest->colorspace, bbox); + temp = fz_new_pixmap_with_bbox(ctx, fz_device_gray, bbox); fz_clear_pixmap(ctx, temp); } else diff --git a/draw/draw_paint.c b/draw/draw_paint.c index 3b02b870..2a5f9607 100644 --- a/draw/draw_paint.c +++ b/draw/draw_paint.c @@ -1,4 +1,4 @@ -#include "fitz.h" +#include "fitz-internal.h" /* @@ -382,8 +382,8 @@ fz_paint_pixmap_with_rect(fz_pixmap *dst, fz_pixmap *src, int alpha, fz_bbox bbo assert(dst->n == src->n); - bbox = fz_intersect_bbox(bbox, fz_bound_pixmap(dst)); - bbox = fz_intersect_bbox(bbox, fz_bound_pixmap(src)); + bbox = fz_intersect_bbox(bbox, fz_pixmap_bbox_no_ctx(dst)); + bbox = fz_intersect_bbox(bbox, fz_pixmap_bbox_no_ctx(src)); x = bbox.x0; y = bbox.y0; @@ -413,8 +413,8 @@ fz_paint_pixmap(fz_pixmap *dst, fz_pixmap *src, int alpha) assert(dst->n == src->n); - bbox = fz_bound_pixmap(dst); - bbox = fz_intersect_bbox(bbox, fz_bound_pixmap(src)); + bbox = fz_pixmap_bbox_no_ctx(dst); + bbox = fz_intersect_bbox(bbox, fz_pixmap_bbox_no_ctx(src)); x = bbox.x0; y = bbox.y0; @@ -445,9 +445,9 @@ fz_paint_pixmap_with_mask(fz_pixmap *dst, fz_pixmap *src, fz_pixmap *msk) assert(dst->n == src->n); assert(msk->n == 1); - bbox = fz_bound_pixmap(dst); - bbox = fz_intersect_bbox(bbox, fz_bound_pixmap(src)); - bbox = fz_intersect_bbox(bbox, fz_bound_pixmap(msk)); + bbox = fz_pixmap_bbox_no_ctx(dst); + bbox = fz_intersect_bbox(bbox, fz_pixmap_bbox_no_ctx(src)); + bbox = fz_intersect_bbox(bbox, fz_pixmap_bbox_no_ctx(msk)); x = bbox.x0; y = bbox.y0; diff --git a/draw/draw_path.c b/draw/draw_path.c index eca7dc08..2ef8cf3a 100644 --- a/draw/draw_path.c +++ b/draw/draw_path.c @@ -1,4 +1,4 @@ -#include "fitz.h" +#include "fitz-internal.h" #define MAX_DEPTH 8 diff --git a/draw/draw_scale.c b/draw/draw_scale.c index 489a2eb9..aceec939 100644 --- a/draw/draw_scale.c +++ b/draw/draw_scale.c @@ -6,7 +6,7 @@ given by taking the source pixmap src, scaling it to width w, and height h, and then positioning it at (frac(x),frac(y)). */ -#include "fitz.h" +#include "fitz-internal.h" /* Do we special case handling of single pixel high/wide images? The * 'purest' handling is given by not special casing them, but certain @@ -349,16 +349,8 @@ add_weight(fz_weights *weights, int j, int i, fz_scale_filter *filter, weight = (int)(256*f+0.5f); /* Ensure i is in range */ - if (i < 0) - { - i = 0; + if (i < 0 || i >= src_w) return; - } - else if (i >= src_w) - { - i = src_w-1; - return; - } if (weight == 0) { /* We add a fudge factor here to allow for extreme downscales diff --git a/draw/draw_simple_scale.c b/draw/draw_simple_scale.c index 6d0ad481..8143b6fd 100644 --- a/draw/draw_simple_scale.c +++ b/draw/draw_simple_scale.c @@ -10,7 +10,7 @@ that return values strictly in the 0..1 range, and uses bytes for intermediate results rather than ints. */ -#include "fitz.h" +#include "fitz-internal.h" /* Do we special case handling of single pixel high/wide images? The * 'purest' handling is given by not special casing them, but certain diff --git a/draw/draw_unpack.c b/draw/draw_unpack.c index 6da5e8a3..f988dcf9 100644 --- a/draw/draw_unpack.c +++ b/draw/draw_unpack.c @@ -1,4 +1,4 @@ -#include "fitz.h" +#include "fitz-internal.h" /* Unpack image samples and optionally pad pixels with opaque alpha */ diff --git a/fitz/base_context.c b/fitz/base_context.c index fe69ff8e..075a3d02 100644 --- a/fitz/base_context.c +++ b/fitz/base_context.c @@ -1,12 +1,4 @@ -#include "fitz.h" - -static fz_obj * -fz_resolve_indirect_null(fz_obj *ref) -{ - return ref; -} - -fz_obj *(*fz_resolve_indirect)(fz_obj*) = fz_resolve_indirect_null; +#include "fitz-internal.h" void fz_free_context(fz_context *ctx) @@ -130,7 +122,9 @@ fz_clone_context_internal(fz_context *ctx) if (ctx == NULL || ctx->alloc == NULL) return NULL; new_ctx = new_context_phase1(ctx->alloc, ctx->locks); - new_ctx->store = fz_store_keep(ctx); + /* Inherit AA defaults from old context. */ + fz_copy_aa_context(new_ctx, ctx); + new_ctx->store = fz_keep_store_context(ctx); new_ctx->glyph_cache = fz_keep_glyph_cache(ctx); new_ctx->font = fz_keep_font_context(ctx); return new_ctx; diff --git a/fitz/base_error.c b/fitz/base_error.c index 6b54fb69..71a32a2e 100644 --- a/fitz/base_error.c +++ b/fitz/base_error.c @@ -1,4 +1,4 @@ -#include "fitz.h" +#include "fitz-internal.h" /* Warning context */ @@ -46,7 +46,7 @@ void fz_warn(fz_context *ctx, char *fmt, ...) static void throw(fz_error_context *ex) { if (ex->top >= 0) { - longjmp(ex->stack[ex->top].buffer, 1); + fz_longjmp(ex->stack[ex->top].buffer, 1); } else { fprintf(stderr, "uncaught exception: %s\n", ex->message); LOGE("uncaught exception: %s\n", ex->message); diff --git a/fitz/base_geometry.c b/fitz/base_geometry.c index fc5ce517..84134179 100644 --- a/fitz/base_geometry.c +++ b/fitz/base_geometry.c @@ -1,4 +1,4 @@ -#include "fitz.h" +#include "fitz-internal.h" #define MAX4(a,b,c,d) MAX(MAX(a,b), MAX(c,d)) #define MIN4(a,b,c,d) MIN(MIN(a,b), MIN(c,d)) diff --git a/fitz/base_hash.c b/fitz/base_hash.c index 630f6b6a..4ba02f4d 100644 --- a/fitz/base_hash.c +++ b/fitz/base_hash.c @@ -1,4 +1,4 @@ -#include "fitz.h" +#include "fitz-internal.h" /* Simple hashtable with open addressing linear probe. @@ -22,6 +22,7 @@ struct fz_hash_table_s int keylen; int size; int load; + int lock; /* -1 or the lock used to protect this hash table */ fz_hash_entry *ents; }; @@ -42,7 +43,7 @@ static unsigned hash(unsigned char *s, int len) } fz_hash_table * -fz_new_hash_table(fz_context *ctx, int initialsize, int keylen) +fz_new_hash_table(fz_context *ctx, int initialsize, int keylen, int lock) { fz_hash_table *table; @@ -52,6 +53,7 @@ fz_new_hash_table(fz_context *ctx, int initialsize, int keylen) table->keylen = keylen; table->size = initialsize; table->load = 0; + table->lock = lock; fz_try(ctx) { table->ents = fz_malloc_array(ctx, table->size, sizeof(fz_hash_entry)); @@ -98,10 +100,45 @@ fz_free_hash(fz_context *ctx, fz_hash_table *table) fz_free(ctx, table); } +static void * +do_hash_insert(fz_context *ctx, fz_hash_table *table, void *key, void *val) +{ + fz_hash_entry *ents; + unsigned size; + unsigned pos; + + ents = table->ents; + size = table->size; + pos = hash(key, table->keylen) % size; + + if (table->lock >= 0) + fz_assert_lock_held(ctx, table->lock); + + while (1) + { + if (!ents[pos].val) + { + memcpy(ents[pos].key, key, table->keylen); + ents[pos].val = val; + table->load ++; + return NULL; + } + + if (memcmp(key, ents[pos].key, table->keylen) == 0) + { + fz_warn(ctx, "assert: overwrite hash slot"); + return ents[pos].val; + } + + pos = (pos + 1) % size; + } +} + static void fz_resize_hash(fz_context *ctx, fz_hash_table *table, int newsize) { fz_hash_entry *oldents = table->ents; + fz_hash_entry *newents = table->ents; int oldsize = table->size; int oldload = table->load; int i; @@ -112,7 +149,22 @@ fz_resize_hash(fz_context *ctx, fz_hash_table *table, int newsize) return; } - table->ents = fz_malloc_array(ctx, newsize, sizeof(fz_hash_entry)); + if (table->lock == FZ_LOCK_ALLOC) + fz_unlock(ctx, FZ_LOCK_ALLOC); + newents = fz_malloc_array(ctx, newsize, sizeof(fz_hash_entry)); + if (table->lock == FZ_LOCK_ALLOC) + fz_lock(ctx, FZ_LOCK_ALLOC); + if (table->lock >= 0) + { + if (table->size >= newsize) + { + /* Someone else fixed it before we could lock! */ + fz_unlock(ctx, table->lock); + fz_free(ctx, newents); + return; + } + } + table->ents = newents; memset(table->ents, 0, sizeof(fz_hash_entry) * newsize); table->size = newsize; table->load = 0; @@ -121,11 +173,15 @@ fz_resize_hash(fz_context *ctx, fz_hash_table *table, int newsize) { if (oldents[i].val) { - fz_hash_insert(ctx, table, oldents[i].key, oldents[i].val); + do_hash_insert(ctx, table, oldents[i].key, oldents[i].val); } } + if (table->lock == FZ_LOCK_ALLOC) + fz_unlock(ctx, FZ_LOCK_ALLOC); fz_free(ctx, oldents); + if (table->lock == FZ_LOCK_ALLOC) + fz_lock(ctx, FZ_LOCK_ALLOC); } void * @@ -135,6 +191,9 @@ fz_hash_find(fz_context *ctx, fz_hash_table *table, void *key) unsigned size = table->size; unsigned pos = hash(key, table->keylen) % size; + if (table->lock >= 0) + fz_assert_lock_held(ctx, table->lock); + while (1) { if (!ents[pos].val) @@ -150,37 +209,12 @@ fz_hash_find(fz_context *ctx, fz_hash_table *table, void *key) void * fz_hash_insert(fz_context *ctx, fz_hash_table *table, void *key, void *val) { - fz_hash_entry *ents; - unsigned size; - unsigned pos; - if (table->load > table->size * 8 / 10) { fz_resize_hash(ctx, table, table->size * 2); } - ents = table->ents; - size = table->size; - pos = hash(key, table->keylen) % size; - - while (1) - { - if (!ents[pos].val) - { - memcpy(ents[pos].key, key, table->keylen); - ents[pos].val = val; - table->load ++; - return NULL; - } - - if (memcmp(key, ents[pos].key, table->keylen) == 0) - { - fz_warn(ctx, "assert: overwrite hash slot"); - return ents[pos].val; - } - - pos = (pos + 1) % size; - } + return do_hash_insert(ctx, table, key, val); } void @@ -191,11 +225,14 @@ fz_hash_remove(fz_context *ctx, fz_hash_table *table, void *key) unsigned pos = hash(key, table->keylen) % size; unsigned hole, look, code; + if (table->lock >= 0) + fz_assert_lock_held(ctx, table->lock); + while (1) { if (!ents[pos].val) { - fz_warn(ctx, "assert: remove inexistent hash entry"); + fz_warn(ctx, "assert: remove non-existent hash entry"); return; } @@ -231,22 +268,22 @@ fz_hash_remove(fz_context *ctx, fz_hash_table *table, void *key) } void -fz_debug_hash(fz_context *ctx, fz_hash_table *table) +fz_print_hash(fz_context *ctx, FILE *out, fz_hash_table *table) { int i, k; - printf("cache load %d / %d\n", table->load, table->size); + fprintf(out, "cache load %d / %d\n", table->load, table->size); for (i = 0; i < table->size; i++) { if (!table->ents[i].val) - printf("table % 4d: empty\n", i); + fprintf(out, "table % 4d: empty\n", i); else { - printf("table % 4d: key=", i); + fprintf(out, "table % 4d: key=", i); for (k = 0; k < MAX_KEY_LEN; k++) - printf("%02x", ((char*)table->ents[i].key)[k]); - printf(" val=$%p\n", table->ents[i].val); + fprintf(out, "%02x", ((char*)table->ents[i].key)[k]); + fprintf(out, " val=$%p\n", table->ents[i].val); } } } diff --git a/fitz/base_memory.c b/fitz/base_memory.c index c9ec2628..32c7ff84 100644 --- a/fitz/base_memory.c +++ b/fitz/base_memory.c @@ -1,4 +1,4 @@ -#include "fitz.h" +#include "fitz-internal.h" static void * do_scavenging_malloc(fz_context *ctx, unsigned int size) diff --git a/fitz/base_string.c b/fitz/base_string.c index dd9f8ea2..8ed08911 100644 --- a/fitz/base_string.c +++ b/fitz/base_string.c @@ -1,11 +1,4 @@ -#include "fitz.h" - -int -fz_is_big_endian(void) -{ - static const int one = 1; - return *(char*)&one == 0; -} +#include "fitz-internal.h" char * fz_strsep(char **stringp, const char *delim) @@ -36,8 +29,8 @@ fz_strlcpy(char *dst, const char *src, int siz) if (n == 0) { if (siz != 0) *d = '\0'; /* NUL-terminate dst */ - while (*s++) - ; + while (*s++) + ; } return(s - src - 1); /* count does not include NUL */ @@ -108,7 +101,7 @@ enum }; int -chartorune(int *rune, char *str) +fz_chartorune(int *rune, char *str) { int c, c1, c2, c3; long l; @@ -183,16 +176,15 @@ bad: } int -runetochar(char *str, int *rune) +fz_runetochar(char *str, int rune) { /* Runes are signed, so convert to unsigned for range check. */ - unsigned long c; + unsigned long c = (unsigned long)rune; /* * one character sequence * 00000-0007F => 00-7F */ - c = *rune; if(c <= Rune1) { str[0] = c; return 1; @@ -240,10 +232,10 @@ runetochar(char *str, int *rune) } int -runelen(int c) +fz_runelen(int c) { char str[10]; - return runetochar(str, &c); + return fz_runetochar(str, c); } float fz_atof(const char *s) @@ -256,10 +248,11 @@ float fz_atof(const char *s) * as we convert to a float. */ errno = 0; d = strtod(s, NULL); - if (errno == ERANGE || d > FLT_MAX || d < -FLT_MAX) { + if (errno == ERANGE || isnan(d)) { /* Return 1.0, as it's a small known value that won't cause a - * divide by 0. */ + divide by 0. */ return 1.0; } + d = CLAMP(d, -FLT_MAX, FLT_MAX); return (float)d; } diff --git a/fitz/crypt_aes.c b/fitz/crypt_aes.c index afdff0fe..4d8c4498 100644 --- a/fitz/crypt_aes.c +++ b/fitz/crypt_aes.c @@ -36,7 +36,7 @@ * http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf */ -#include "fitz.h" +#include "fitz-internal.h" #define aes_context fz_aes diff --git a/fitz/crypt_arc4.c b/fitz/crypt_arc4.c index 272891ce..596bf652 100644 --- a/fitz/crypt_arc4.c +++ b/fitz/crypt_arc4.c @@ -21,7 +21,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "fitz.h" +#include "fitz-internal.h" void fz_arc4_init(fz_arc4 *arc4, const unsigned char *key, unsigned keylen) diff --git a/fitz/crypt_md5.c b/fitz/crypt_md5.c index b6e06845..87c0909d 100644 --- a/fitz/crypt_md5.c +++ b/fitz/crypt_md5.c @@ -23,7 +23,7 @@ These notices must be retained in any copies of any part of this documentation and/or software. */ -#include "fitz.h" +#include "fitz-internal.h" /* Constants for MD5Transform routine */ enum diff --git a/fitz/crypt_sha2.c b/fitz/crypt_sha2.c index f17146c6..64284cfa 100644 --- a/fitz/crypt_sha2.c +++ b/fitz/crypt_sha2.c @@ -7,7 +7,7 @@ This file has been put into the public domain. You can do whatever you want with this file. */ -#include "fitz.h" +#include "fitz-internal.h" static inline int isbigendian(void) { diff --git a/fitz/dev_bbox.c b/fitz/dev_bbox.c index 636ceb94..163780d0 100644 --- a/fitz/dev_bbox.c +++ b/fitz/dev_bbox.c @@ -1,4 +1,4 @@ -#include "fitz.h" +#include "fitz-internal.h" /* TODO: add clip stack and use to intersect bboxes */ @@ -47,7 +47,7 @@ fz_bbox_fill_shade(fz_device *dev, fz_shade *shade, fz_matrix ctm, float alpha) } static void -fz_bbox_fill_image(fz_device *dev, fz_pixmap *image, fz_matrix ctm, float alpha) +fz_bbox_fill_image(fz_device *dev, fz_image *image, fz_matrix ctm, float alpha) { fz_bbox *result = dev->user; fz_bbox bbox = fz_round_rect(fz_transform_rect(ctm, fz_unit_rect)); @@ -55,7 +55,7 @@ fz_bbox_fill_image(fz_device *dev, fz_pixmap *image, fz_matrix ctm, float alpha) } static void -fz_bbox_fill_image_mask(fz_device *dev, fz_pixmap *image, fz_matrix ctm, +fz_bbox_fill_image_mask(fz_device *dev, fz_image *image, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha) { fz_bbox_fill_image(dev, image, ctm, alpha); diff --git a/fitz/dev_list.c b/fitz/dev_list.c index adc691d0..d0dfabc5 100644 --- a/fitz/dev_list.c +++ b/fitz/dev_list.c @@ -1,4 +1,4 @@ -#include "fitz.h" +#include "fitz-internal.h" typedef struct fz_display_node_s fz_display_node; @@ -37,7 +37,7 @@ struct fz_display_node_s fz_path *path; fz_text *text; fz_shade *shade; - fz_pixmap *image; + fz_image *image; int blendmode; } item; fz_stroke_state *stroke; @@ -207,7 +207,7 @@ fz_free_display_node(fz_context *ctx, fz_display_node *node) case FZ_CMD_FILL_IMAGE: case FZ_CMD_FILL_IMAGE_MASK: case FZ_CMD_CLIP_IMAGE_MASK: - fz_drop_pixmap(ctx, node->item.image); + fz_drop_image(ctx, node->item.image); break; case FZ_CMD_POP_CLIP: case FZ_CMD_BEGIN_MASK: @@ -435,35 +435,35 @@ fz_list_fill_shade(fz_device *dev, fz_shade *shade, fz_matrix ctm, float alpha) } static void -fz_list_fill_image(fz_device *dev, fz_pixmap *image, fz_matrix ctm, float alpha) +fz_list_fill_image(fz_device *dev, fz_image *image, fz_matrix ctm, float alpha) { fz_display_node *node; node = fz_new_display_node(dev->ctx, FZ_CMD_FILL_IMAGE, ctm, NULL, NULL, alpha); node->rect = fz_transform_rect(ctm, fz_unit_rect); - node->item.image = fz_keep_pixmap(dev->ctx, image); + node->item.image = fz_keep_image(dev->ctx, image); fz_append_display_node(dev->user, node); } static void -fz_list_fill_image_mask(fz_device *dev, fz_pixmap *image, fz_matrix ctm, +fz_list_fill_image_mask(fz_device *dev, fz_image *image, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha) { fz_display_node *node; node = fz_new_display_node(dev->ctx, FZ_CMD_FILL_IMAGE_MASK, ctm, colorspace, color, alpha); node->rect = fz_transform_rect(ctm, fz_unit_rect); - node->item.image = fz_keep_pixmap(dev->ctx, image); + node->item.image = fz_keep_image(dev->ctx, image); fz_append_display_node(dev->user, node); } static void -fz_list_clip_image_mask(fz_device *dev, fz_pixmap *image, fz_rect *rect, fz_matrix ctm) +fz_list_clip_image_mask(fz_device *dev, fz_image *image, fz_rect *rect, fz_matrix ctm) { fz_display_node *node; node = fz_new_display_node(dev->ctx, FZ_CMD_CLIP_IMAGE_MASK, ctm, NULL, NULL, 0); node->rect = fz_transform_rect(ctm, fz_unit_rect); if (rect) node->rect = fz_intersect_rect(node->rect, *rect); - node->item.image = fz_keep_pixmap(dev->ctx, image); + node->item.image = fz_keep_image(dev->ctx, image); fz_append_display_node(dev->user, node); } diff --git a/fitz/dev_null.c b/fitz/dev_null.c index b4ba5cbe..886cebe1 100644 --- a/fitz/dev_null.c +++ b/fitz/dev_null.c @@ -1,4 +1,4 @@ -#include "fitz.h" +#include "fitz-internal.h" fz_device * fz_new_device(fz_context *ctx, void *user) @@ -103,14 +103,14 @@ fz_fill_shade(fz_device *dev, fz_shade *shade, fz_matrix ctm, float alpha) } void -fz_fill_image(fz_device *dev, fz_pixmap *image, fz_matrix ctm, float alpha) +fz_fill_image(fz_device *dev, fz_image *image, fz_matrix ctm, float alpha) { if (dev->fill_image) dev->fill_image(dev, image, ctm, alpha); } void -fz_fill_image_mask(fz_device *dev, fz_pixmap *image, fz_matrix ctm, +fz_fill_image_mask(fz_device *dev, fz_image *image, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha) { if (dev->fill_image_mask) @@ -118,7 +118,7 @@ fz_fill_image_mask(fz_device *dev, fz_pixmap *image, fz_matrix ctm, } void -fz_clip_image_mask(fz_device *dev, fz_pixmap *image, fz_rect *rect, fz_matrix ctm) +fz_clip_image_mask(fz_device *dev, fz_image *image, fz_rect *rect, fz_matrix ctm) { if (dev->clip_image_mask) dev->clip_image_mask(dev, image, rect, ctm); diff --git a/fitz/dev_text.c b/fitz/dev_text.c index d38fab21..7a059e5a 100644 --- a/fitz/dev_text.c +++ b/fitz/dev_text.c @@ -1,7 +1,8 @@ -#include "fitz.h" +#include "fitz-internal.h" #define LINE_DIST 0.9f #define SPACE_DIST 0.2f +#define PARAGRAPH_DIST 0.5f #include <ft2build.h> #include FT_FREETYPE_H @@ -11,60 +12,211 @@ typedef struct fz_text_device_s fz_text_device; struct fz_text_device_s { + fz_text_sheet *sheet; + fz_text_page *page; + fz_text_line cur_line; + fz_text_span cur_span; fz_point point; - fz_text_span *head; - fz_text_span *span; }; -fz_text_span * -fz_new_text_span(fz_context *ctx) +fz_text_sheet * +fz_new_text_sheet(fz_context *ctx) { - fz_text_span *span; - span = fz_malloc_struct(ctx, fz_text_span); - span->font = NULL; - span->wmode = 0; - span->size = 0; - span->len = 0; - span->cap = 0; - span->text = NULL; - span->next = NULL; - span->eol = 0; - return span; + fz_text_sheet *sheet = fz_malloc(ctx, sizeof *sheet); + sheet->maxid = 0; + sheet->style = NULL; + return sheet; } void -fz_free_text_span(fz_context *ctx, fz_text_span *span) +fz_free_text_sheet(fz_context *ctx, fz_text_sheet *sheet) +{ + fz_text_style *style = sheet->style; + while (style) + { + fz_text_style *next = style->next; + fz_drop_font(ctx, style->font); + fz_free(ctx, style); + style = next; + } +} + +static fz_text_style * +fz_lookup_text_style_imp(fz_context *ctx, fz_text_sheet *sheet, + float size, fz_font *font, int wmode, int script) +{ + fz_text_style *style; + + for (style = sheet->style; style; style = style->next) + { + if (style->font == font && + style->size == size && + style->wmode == wmode && + style->script == script) /* FIXME: others */ + { + return style; + } + } + + /* Better make a new one and add it to our list */ + style = fz_malloc(ctx, sizeof *style); + style->id = sheet->maxid++; + style->font = fz_keep_font(ctx, font); + style->size = size; + style->wmode = wmode; + style->script = script; + style->next = sheet->style; + sheet->style = style; + return style; +} + +static fz_text_style * +fz_lookup_text_style(fz_context *ctx, fz_text_sheet *sheet, fz_text *text, fz_matrix *ctm, + fz_colorspace *colorspace, float *color, float alpha, fz_stroke_state *stroke) { - fz_text_span *next; + float size = 1.0f; + fz_font *font = text ? text->font : NULL; + int wmode = text ? text->wmode : 0; + if (ctm && text) + { + fz_matrix tm = text->trm; + fz_matrix trm; + tm.e = 0; + tm.f = 0; + trm = fz_concat(tm, *ctm); + size = fz_matrix_expansion(trm); + } + return fz_lookup_text_style_imp(ctx, sheet, size, font, wmode, 0); +} - while (span) +fz_text_page * +fz_new_text_page(fz_context *ctx, fz_rect mediabox) +{ + fz_text_page *page = fz_malloc(ctx, sizeof(*page)); + page->mediabox = mediabox; + page->len = 0; + page->cap = 0; + page->blocks = NULL; + return page; +} + +void +fz_free_text_page(fz_context *ctx, fz_text_page *page) +{ + fz_text_block *block; + fz_text_line *line; + fz_text_span *span; + for (block = page->blocks; block < page->blocks + page->len; block++) { - if (span->font) - fz_drop_font(ctx, span->font); - next = span->next; - fz_free(ctx, span->text); - fz_free(ctx, span); - span = next; + for (line = block->lines; line < block->lines + block->len; line++) + { + for (span = line->spans; span < line->spans + line->len; span++) + { + fz_free(ctx, span->text); + } + fz_free(ctx, line->spans); + } + fz_free(ctx, block->lines); } + fz_free(ctx, page->blocks); + fz_free(ctx, page); } static void -fz_add_text_char_imp(fz_context *ctx, fz_text_span *span, int c, fz_bbox bbox) +append_char(fz_context *ctx, fz_text_span *span, int c, fz_rect bbox) { - if (span->len + 1 >= span->cap) + if (span->len == span->cap) { - span->cap = span->cap > 1 ? (span->cap * 3) / 2 : 80; - span->text = fz_resize_array(ctx, span->text, span->cap, sizeof(fz_text_char)); + span->cap = MAX(64, span->cap * 2); + span->text = fz_resize_array(ctx, span->text, span->cap, sizeof(*span->text)); } + span->bbox = fz_union_rect(span->bbox, bbox); span->text[span->len].c = c; span->text[span->len].bbox = bbox; - span->len ++; + span->len++; +} + +static void +init_span(fz_context *ctx, fz_text_span *span, fz_text_style *style) +{ + span->style = style; + span->bbox = fz_empty_rect; + span->len = span->cap = 0; + span->text = NULL; +} + +static void +append_span(fz_context *ctx, fz_text_line *line, fz_text_span *span) +{ + if (line->len == line->cap) + { + line->cap = MAX(8, line->cap * 2); + line->spans = fz_resize_array(ctx, line->spans, line->cap, sizeof(*line->spans)); + } + line->bbox = fz_union_rect(line->bbox, span->bbox); + line->spans[line->len++] = *span; } -static fz_bbox -fz_split_bbox(fz_bbox bbox, int i, int n) +static void +init_line(fz_context *ctx, fz_text_line *line) +{ + line->bbox = fz_empty_rect; + line->len = line->cap = 0; + line->spans = NULL; +} + +static void +append_line(fz_context *ctx, fz_text_block *block, fz_text_line *line) { - float w = (float)(bbox.x1 - bbox.x0) / n; + if (block->len == block->cap) + { + block->cap = MAX(16, block->cap * 2); + block->lines = fz_resize_array(ctx, block->lines, block->cap, sizeof *block->lines); + } + block->bbox = fz_union_rect(block->bbox, line->bbox); + block->lines[block->len++] = *line; +} + +static fz_text_block * +lookup_block_for_line(fz_context *ctx, fz_text_page *page, fz_text_line *line) +{ + float size = line->len > 0 && line->spans[0].len > 0 ? line->spans[0].style->size : 1; + int i; + + for (i = 0; i < page->len; i++) + { + fz_text_block *block = page->blocks + i; + int w = block->bbox.x1 - block->bbox.x0; + if (block->bbox.y0 - line->bbox.y1 < size * PARAGRAPH_DIST) + if (line->bbox.x0 < block->bbox.x1 && line->bbox.x1 > block->bbox.x0) + if (ABS(line->bbox.x0 - block->bbox.x0) < w / 4) + return block; + } + + if (page->len == page->cap) + { + page->cap = MAX(16, page->cap * 2); + page->blocks = fz_resize_array(ctx, page->blocks, page->cap, sizeof(*page->blocks)); + } + + page->blocks[page->len].bbox = fz_empty_rect; + page->blocks[page->len].len = 0; + page->blocks[page->len].cap = 0; + page->blocks[page->len].lines = NULL; + + return &page->blocks[page->len++]; +} + +static void +insert_line(fz_context *ctx, fz_text_page *page, fz_text_line *line) +{ + append_line(ctx, lookup_block_for_line(ctx, page, line), line); +} + +static fz_rect +fz_split_bbox(fz_rect bbox, int i, int n) +{ + float w = (bbox.x1 - bbox.x0) / n; float x0 = bbox.x0; bbox.x0 = x0 + i * w; bbox.x1 = x0 + (i + 1) * w; @@ -72,154 +224,71 @@ fz_split_bbox(fz_bbox bbox, int i, int n) } static void -fz_add_text_char(fz_context *ctx, fz_text_span **last, fz_font *font, float size, int wmode, int c, fz_bbox bbox) +fz_flush_text_line(fz_context *ctx, fz_text_device *dev, fz_text_style *style) { - fz_text_span *span = *last; - - if (!span->font) - { - span->font = fz_keep_font(ctx, font); - span->size = size; - } + append_span(ctx, &dev->cur_line, &dev->cur_span); + insert_line(ctx, dev->page, &dev->cur_line); + init_span(ctx, &dev->cur_span, style); + init_line(ctx, &dev->cur_line); +} - if ((span->font != font || span->size != size || span->wmode != wmode) && c != 32) +static void +fz_add_text_char_imp(fz_context *ctx, fz_text_device *dev, fz_text_style *style, int c, fz_rect bbox) +{ + if (!dev->cur_span.style) + dev->cur_span.style = style; + if (style != dev->cur_span.style) { - span = fz_new_text_span(ctx); - span->font = fz_keep_font(ctx, font); - span->size = size; - span->wmode = wmode; - (*last)->next = span; - *last = span; + append_span(ctx, &dev->cur_line, &dev->cur_span); + init_span(ctx, &dev->cur_span, style); } + append_char(ctx, &dev->cur_span, c, bbox); +} +static void +fz_add_text_char(fz_context *ctx, fz_text_device *dev, fz_text_style *style, int c, fz_rect bbox) +{ switch (c) { case -1: /* ignore when one unicode character maps to multiple glyphs */ break; case 0xFB00: /* ff */ - fz_add_text_char_imp(ctx, span, 'f', fz_split_bbox(bbox, 0, 2)); - fz_add_text_char_imp(ctx, span, 'f', fz_split_bbox(bbox, 1, 2)); + fz_add_text_char_imp(ctx, dev, style, 'f', fz_split_bbox(bbox, 0, 2)); + fz_add_text_char_imp(ctx, dev, style, 'f', fz_split_bbox(bbox, 1, 2)); break; case 0xFB01: /* fi */ - fz_add_text_char_imp(ctx, span, 'f', fz_split_bbox(bbox, 0, 2)); - fz_add_text_char_imp(ctx, span, 'i', fz_split_bbox(bbox, 1, 2)); + fz_add_text_char_imp(ctx, dev, style, 'f', fz_split_bbox(bbox, 0, 2)); + fz_add_text_char_imp(ctx, dev, style, 'i', fz_split_bbox(bbox, 1, 2)); break; case 0xFB02: /* fl */ - fz_add_text_char_imp(ctx, span, 'f', fz_split_bbox(bbox, 0, 2)); - fz_add_text_char_imp(ctx, span, 'l', fz_split_bbox(bbox, 1, 2)); + fz_add_text_char_imp(ctx, dev, style, 'f', fz_split_bbox(bbox, 0, 2)); + fz_add_text_char_imp(ctx, dev, style, 'l', fz_split_bbox(bbox, 1, 2)); break; case 0xFB03: /* ffi */ - fz_add_text_char_imp(ctx, span, 'f', fz_split_bbox(bbox, 0, 3)); - fz_add_text_char_imp(ctx, span, 'f', fz_split_bbox(bbox, 1, 3)); - fz_add_text_char_imp(ctx, span, 'i', fz_split_bbox(bbox, 2, 3)); + fz_add_text_char_imp(ctx, dev, style, 'f', fz_split_bbox(bbox, 0, 3)); + fz_add_text_char_imp(ctx, dev, style, 'f', fz_split_bbox(bbox, 1, 3)); + fz_add_text_char_imp(ctx, dev, style, 'i', fz_split_bbox(bbox, 2, 3)); break; case 0xFB04: /* ffl */ - fz_add_text_char_imp(ctx, span, 'f', fz_split_bbox(bbox, 0, 3)); - fz_add_text_char_imp(ctx, span, 'f', fz_split_bbox(bbox, 1, 3)); - fz_add_text_char_imp(ctx, span, 'l', fz_split_bbox(bbox, 2, 3)); + fz_add_text_char_imp(ctx, dev, style, 'f', fz_split_bbox(bbox, 0, 3)); + fz_add_text_char_imp(ctx, dev, style, 'f', fz_split_bbox(bbox, 1, 3)); + fz_add_text_char_imp(ctx, dev, style, 'l', fz_split_bbox(bbox, 2, 3)); break; case 0xFB05: /* long st */ case 0xFB06: /* st */ - fz_add_text_char_imp(ctx, span, 's', fz_split_bbox(bbox, 0, 2)); - fz_add_text_char_imp(ctx, span, 't', fz_split_bbox(bbox, 1, 2)); + fz_add_text_char_imp(ctx, dev, style, 's', fz_split_bbox(bbox, 0, 2)); + fz_add_text_char_imp(ctx, dev, style, 't', fz_split_bbox(bbox, 1, 2)); break; default: - fz_add_text_char_imp(ctx, span, c, bbox); + fz_add_text_char_imp(ctx, dev, style, c, bbox); break; } } static void -fz_divide_text_chars(fz_text_span **last, int n, fz_bbox bbox) -{ - fz_text_span *span = *last; - int i, x; - x = span->len - n; - if (x >= 0) - for (i = 0; i < n; i++) - span->text[x + i].bbox = fz_split_bbox(bbox, i, n); -} - -static void -fz_add_text_newline(fz_context *ctx, fz_text_span **last, fz_font *font, float size, int wmode) -{ - fz_text_span *span; - span = fz_new_text_span(ctx); - span->font = fz_keep_font(ctx, font); - span->size = size; - span->wmode = wmode; - (*last)->eol = 1; - (*last)->next = span; - *last = span; -} - -void -fz_debug_text_span_xml(fz_text_span *span) -{ - char buf[10]; - int c, n, k, i; - - while (span) - { - printf("<span font=\"%s\" size=\"%g\" wmode=\"%d\" eol=\"%d\">\n", - span->font ? span->font->name : "NULL", span->size, span->wmode, span->eol); - - for (i = 0; i < span->len; i++) - { - printf("\t<char ucs=\""); - c = span->text[i].c; - if (c < 128) - putchar(c); - else - { - n = runetochar(buf, &c); - for (k = 0; k < n; k++) - putchar(buf[k]); - } - printf("\" bbox=\"%d %d %d %d\" />\n", - span->text[i].bbox.x0, - span->text[i].bbox.y0, - span->text[i].bbox.x1, - span->text[i].bbox.y1); - } - - printf("</span>\n"); - - span = span->next; - } -} - -void -fz_debug_text_span(fz_text_span *span) -{ - char buf[10]; - int c, n, k, i; - - while (span) - { - for (i = 0; i < span->len; i++) - { - c = span->text[i].c; - if (c < 128) - putchar(c); - else - { - n = runetochar(buf, &c); - for (k = 0; k < n; k++) - putchar(buf[k]); - } - } - - if (span->eol) - putchar('\n'); - - span = span->next; - } -} - -static void -fz_text_extract_span(fz_context *ctx, fz_text_span **last, fz_text *text, fz_matrix ctm, fz_point *pen) +fz_text_extract(fz_context *ctx, fz_text_device *dev, fz_text *text, fz_matrix ctm, fz_text_style *style) { + fz_point *pen = &dev->point; fz_font *font = text->font; FT_Face face = font->ft_face; fz_matrix tm = text->trm; @@ -233,19 +302,21 @@ fz_text_extract_span(fz_context *ctx, fz_text_span **last, fz_text *text, fz_mat float ascender = 1; float descender = 0; int multi; - int i, err; + int i, j, err; + int lastchar = ' '; if (text->len == 0) return; - fz_lock(ctx, FZ_LOCK_FREETYPE); if (font->ft_face) { + fz_lock(ctx, FZ_LOCK_FREETYPE); err = FT_Set_Char_Size(font->ft_face, 64, 64, 72, 72); if (err) fz_warn(ctx, "freetype set character size: %s", ft_error_string(err)); ascender = (float)face->ascender / face->units_per_EM; descender = (float)face->descender / face->units_per_EM; + fz_unlock(ctx, FZ_LOCK_FREETYPE); } rect = fz_empty_rect; @@ -264,6 +335,7 @@ fz_text_extract_span(fz_context *ctx, fz_text_span **last, fz_text *text, fz_mat tm.e = 0; tm.f = 0; trm = fz_concat(tm, ctm); + dir = fz_transform_vector(trm, dir); dist = sqrtf(dir.x * dir.x + dir.y * dir.y); ndir.x = dir.x / dist; @@ -271,19 +343,8 @@ fz_text_extract_span(fz_context *ctx, fz_text_span **last, fz_text *text, fz_mat size = fz_matrix_expansion(trm); - multi = 1; - for (i = 0; i < text->len; i++) { - if (text->items[i].gid < 0) - { - fz_add_text_char(ctx, last, font, size, text->wmode, text->items[i].ucs, fz_round_rect(rect)); - multi ++; - fz_divide_text_chars(last, multi, fz_round_rect(rect)); - continue; - } - multi = 1; - /* Calculate new pen location and delta */ tm.e = text->items[i].x; tm.f = text->items[i].y; @@ -305,20 +366,19 @@ fz_text_extract_span(fz_context *ctx, fz_text_span **last, fz_text *text, fz_mat if (dist > size * LINE_DIST) { - fz_add_text_newline(ctx, last, font, size, text->wmode); + fz_flush_text_line(ctx, dev, style); + lastchar = ' '; } - else if (fabsf(dot) > 0.95f && dist > size * SPACE_DIST) + else if (fabsf(dot) > 0.95f && dist > size * SPACE_DIST && lastchar != ' ') { - if ((*last)->len > 0 && (*last)->text[(*last)->len - 1].c != ' ') - { - fz_rect spacerect; - spacerect.x0 = -0.2f; - spacerect.y0 = 0; - spacerect.x1 = 0; - spacerect.y1 = 1; - spacerect = fz_transform_rect(trm, spacerect); - fz_add_text_char(ctx, last, font, size, text->wmode, ' ', fz_round_rect(spacerect)); - } + fz_rect spacerect; + spacerect.x0 = -0.2f; + spacerect.y0 = 0; + spacerect.x1 = 0; + spacerect.y1 = 1; + spacerect = fz_transform_rect(trm, spacerect); + fz_add_text_char(ctx, dev, style, ' ', spacerect); + lastchar = ' '; } } @@ -331,8 +391,13 @@ fz_text_extract_span(fz_context *ctx, fz_text_span **last, fz_text *text, fz_mat /* TODO: freetype returns broken vertical metrics */ /* if (text->wmode) mask |= FT_LOAD_VERTICAL_LAYOUT; */ + fz_lock(ctx, FZ_LOCK_FREETYPE); + err = FT_Set_Char_Size(font->ft_face, 64, 64, 72, 72); + if (err) + fz_warn(ctx, "freetype set character size: %s", ft_error_string(err)); FT_Get_Advance(font->ft_face, text->items[i].gid, mask, &ftadv); adv = ftadv / 65536.0f; + fz_unlock(ctx, FZ_LOCK_FREETYPE); rect.x0 = 0; rect.y0 = descender; @@ -352,9 +417,27 @@ fz_text_extract_span(fz_context *ctx, fz_text_span **last, fz_text *text, fz_mat pen->x = trm.e + dir.x * adv; pen->y = trm.f + dir.y * adv; - fz_add_text_char(ctx, last, font, size, text->wmode, text->items[i].ucs, fz_round_rect(rect)); + /* Check for one glyph to many char mapping */ + for (j = i + 1; j < text->len; j++) + if (text->items[j].gid >= 0) + break; + multi = j - i; + + if (multi == 1) + { + fz_add_text_char(ctx, dev, style, text->items[i].ucs, rect); + } + else + { + for (j = 0; j < multi; j++) + { + fz_rect part = fz_split_bbox(rect, j, multi); + fz_add_text_char(ctx, dev, style, text->items[i].ucs, part); + } + } + + lastchar = text->items[i].ucs; } - fz_unlock(ctx, FZ_LOCK_FREETYPE); } static void @@ -362,7 +445,9 @@ fz_text_fill_text(fz_device *dev, fz_text *text, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha) { fz_text_device *tdev = dev->user; - fz_text_extract_span(dev->ctx, &tdev->span, text, ctm, &tdev->point); + fz_text_style *style; + style = fz_lookup_text_style(dev->ctx, tdev->sheet, text, &ctm, colorspace, color, alpha, NULL); + fz_text_extract(dev->ctx, tdev, text, ctm, style); } static void @@ -370,36 +455,57 @@ fz_text_stroke_text(fz_device *dev, fz_text *text, fz_stroke_state *stroke, fz_m fz_colorspace *colorspace, float *color, float alpha) { fz_text_device *tdev = dev->user; - fz_text_extract_span(dev->ctx, &tdev->span, text, ctm, &tdev->point); + fz_text_style *style; + style = fz_lookup_text_style(dev->ctx, tdev->sheet, text, &ctm, colorspace, color, alpha, stroke); + fz_text_extract(dev->ctx, tdev, text, ctm, style); } static void fz_text_clip_text(fz_device *dev, fz_text *text, fz_matrix ctm, int accumulate) { fz_text_device *tdev = dev->user; - fz_text_extract_span(dev->ctx, &tdev->span, text, ctm, &tdev->point); + fz_text_style *style; + style = fz_lookup_text_style(dev->ctx, tdev->sheet, text, &ctm, NULL, NULL, 0, NULL); + fz_text_extract(dev->ctx, tdev, text, ctm, style); } static void fz_text_clip_stroke_text(fz_device *dev, fz_text *text, fz_stroke_state *stroke, fz_matrix ctm) { fz_text_device *tdev = dev->user; - fz_text_extract_span(dev->ctx, &tdev->span, text, ctm, &tdev->point); + fz_text_style *style; + style = fz_lookup_text_style(dev->ctx, tdev->sheet, text, &ctm, NULL, NULL, 0, stroke); + fz_text_extract(dev->ctx, tdev, text, ctm, style); } static void fz_text_ignore_text(fz_device *dev, fz_text *text, fz_matrix ctm) { fz_text_device *tdev = dev->user; - fz_text_extract_span(dev->ctx, &tdev->span, text, ctm, &tdev->point); + fz_text_style *style; + style = fz_lookup_text_style(dev->ctx, tdev->sheet, text, &ctm, NULL, NULL, 0, NULL); + fz_text_extract(dev->ctx, tdev, text, ctm, style); +} + +static int cmp_block(const void *av, const void *bv) +{ + const fz_text_block *a = av; + const fz_text_block *b = bv; + int x = a->bbox.x0 - b->bbox.x0; + if (x) return x; + return -(a->bbox.y0 - b->bbox.y0); } static void fz_text_free_user(fz_device *dev) { + fz_context *ctx = dev->ctx; fz_text_device *tdev = dev->user; - tdev->span->eol = 1; + append_span(ctx, &tdev->cur_line, &tdev->cur_span); + insert_line(ctx, tdev->page, &tdev->cur_line); + + qsort(tdev->page->blocks, tdev->page->len, sizeof *tdev->page->blocks, cmp_block); /* TODO: unicode NFC normalization */ /* TODO: bidi logical reordering */ @@ -408,15 +514,19 @@ fz_text_free_user(fz_device *dev) } fz_device * -fz_new_text_device(fz_context *ctx, fz_text_span *root) +fz_new_text_device(fz_context *ctx, fz_text_sheet *sheet, fz_text_page *page) { fz_device *dev; + fz_text_device *tdev = fz_malloc_struct(ctx, fz_text_device); - tdev->head = root; - tdev->span = root; + tdev->sheet = sheet; + tdev->page = page; tdev->point.x = -1; tdev->point.y = -1; + init_line(ctx, &tdev->cur_line); + init_span(ctx, &tdev->cur_span, NULL); + dev = fz_new_device(ctx, tdev); dev->hints = FZ_IGNORE_IMAGE | FZ_IGNORE_SHADE; dev->free_user = fz_text_free_user; @@ -427,3 +537,209 @@ fz_new_text_device(fz_context *ctx, fz_text_span *root) dev->ignore_text = fz_text_ignore_text; return dev; } + +/* XML, HTML and plain-text output */ + +static int font_is_bold(fz_font *font) +{ + FT_Face face = font->ft_face; + if (face && (face->style_flags & FT_STYLE_FLAG_BOLD)) + return 1; + if (strstr(font->name, "Bold")) + return 1; + return 0; +} + +static int font_is_italic(fz_font *font) +{ + FT_Face face = font->ft_face; + if (face && (face->style_flags & FT_STYLE_FLAG_ITALIC)) + return 1; + if (strstr(font->name, "Italic") || strstr(font->name, "Oblique")) + return 1; + return 0; +} + +static void +fz_print_style_begin(FILE *out, fz_text_style *style) +{ + int script = style->script; + fprintf(out, "<span class=\"s%d\">", style->id); + while (script-- > 0) + fprintf(out, "<sup>"); + while (++script < 0) + fprintf(out, "<sub>"); +} + +static void +fz_print_style_end(FILE *out, fz_text_style *style) +{ + int script = style->script; + while (script-- > 0) + fprintf(out, "</sup>"); + while (++script < 0) + fprintf(out, "</sub>"); + fprintf(out, "</span>"); +} + +static void +fz_print_style(FILE *out, fz_text_style *style) +{ + char *s = strchr(style->font->name, '+'); + s = s ? s + 1 : style->font->name; + fprintf(out, "span.s%d{font-family:\"%s\";font-size:%gpt;", + style->id, s, style->size); + if (font_is_italic(style->font)) + fprintf(out, "font-style:italic;"); + if (font_is_bold(style->font)) + fprintf(out, "font-weight:bold;"); + fprintf(out, "}\n"); +} + +void +fz_print_text_sheet(fz_context *ctx, FILE *out, fz_text_sheet *sheet) +{ + fz_text_style *style; + for (style = sheet->style; style; style = style->next) + fz_print_style(out, style); +} + +void +fz_print_text_page_html(fz_context *ctx, FILE *out, fz_text_page *page) +{ + int block_n, line_n, span_n, ch_n; + fz_text_style *style = NULL; + fz_text_block *block; + fz_text_line *line; + fz_text_span *span; + + fprintf(out, "<div class=\"page\">\n"); + + for (block_n = 0; block_n < page->len; block_n++) + { + block = &page->blocks[block_n]; + fprintf(out, "<div class=\"block\">\n"); + for (line_n = 0; line_n < block->len; line_n++) + { + line = &block->lines[line_n]; + fprintf(out, "<p>"); + style = NULL; + + for (span_n = 0; span_n < line->len; span_n++) + { + span = &line->spans[span_n]; + if (style != span->style) + { + if (style != NULL) + fz_print_style_end(out, style); + fz_print_style_begin(out, span->style); + style = span->style; + } + + for (ch_n = 0; ch_n < span->len; ch_n++) + { + fz_text_char *ch = &span->text[ch_n]; + if (ch->c == '<') + fprintf(out, "<"); + else if (ch->c == '>') + fprintf(out, ">"); + else if (ch->c == '&') + fprintf(out, "&"); + else if (ch->c >= 32 && ch->c <= 127) + fprintf(out, "%c", ch->c); + else + fprintf(out, "&#x%x;", ch->c); + } + } + fz_print_style_end(out, style); + fprintf(out, "</p>\n"); + } + fprintf(out, "</div>\n"); + } + + fprintf(out, "</div>\n"); +} + +void +fz_print_text_page_xml(fz_context *ctx, FILE *out, fz_text_page *page) +{ + fz_text_block *block; + fz_text_line *line; + fz_text_span *span; + fz_text_char *ch; + char *s; + + fprintf(out, "<page>\n"); + for (block = page->blocks; block < page->blocks + page->len; block++) + { + fprintf(out, "<block bbox=\"%g %g %g %g\">\n", + block->bbox.x0, block->bbox.y0, block->bbox.x1, block->bbox.y1); + for (line = block->lines; line < block->lines + block->len; line++) + { + fprintf(out, "<line bbox=\"%g %g %g %g\">\n", + line->bbox.x0, line->bbox.y0, line->bbox.x1, line->bbox.y1); + for (span = line->spans; span < line->spans + line->len; span++) + { + fz_text_style *style = span->style; + s = strchr(style->font->name, '+'); + s = s ? s + 1 : style->font->name; + fprintf(out, "<span bbox=\"%g %g %g %g\" font=\"%s\" size=\"%g\">\n", + span->bbox.x0, span->bbox.y0, span->bbox.x1, span->bbox.y1, + s, style->size); + for (ch = span->text; ch < span->text + span->len; ch++) + { + fprintf(out, "<char bbox=\"%g %g %g %g\" c=\"", + ch->bbox.x0, ch->bbox.y0, ch->bbox.x1, ch->bbox.y1); + switch (ch->c) + { + case '<': fprintf(out, "<"); break; + case '>': fprintf(out, ">"); break; + case '&': fprintf(out, "&"); break; + case '"': fprintf(out, """); break; + case '\'': fprintf(out, "'"); break; + default: + if (ch->c >= 32 && ch->c <= 127) + fprintf(out, "%c", ch->c); + else + fprintf(out, "&#x%x;", ch->c); + break; + } + fprintf(out, "\"/>\n"); + } + fprintf(out, "</span>\n"); + } + fprintf(out, "</line>\n"); + } + fprintf(out, "</block>\n"); + } + fprintf(out, "</page>\n"); +} + +void +fz_print_text_page(fz_context *ctx, FILE *out, fz_text_page *page) +{ + fz_text_block *block; + fz_text_line *line; + fz_text_span *span; + fz_text_char *ch; + char utf[10]; + int i, n; + + for (block = page->blocks; block < page->blocks + page->len; block++) + { + for (line = block->lines; line < block->lines + block->len; line++) + { + for (span = line->spans; span < line->spans + line->len; span++) + { + for (ch = span->text; ch < span->text + span->len; ch++) + { + n = fz_runetochar(utf, ch->c); + for (i = 0; i < n; i++) + putc(utf[i], out); + } + } + fprintf(out, "\n"); + } + fprintf(out, "\n"); + } +} diff --git a/fitz/dev_trace.c b/fitz/dev_trace.c index 1c2e1ed1..b3c73ff2 100644 --- a/fitz/dev_trace.c +++ b/fitz/dev_trace.c @@ -1,4 +1,4 @@ -#include "fitz.h" +#include "fitz-internal.h" static void fz_trace_matrix(fz_matrix ctm) @@ -145,7 +145,7 @@ fz_trace_fill_text(fz_device *dev, fz_text *text, fz_matrix ctm, fz_trace_matrix(ctm); fz_trace_trm(text->trm); printf(">\n"); - fz_debug_text(dev->ctx, text, 0); + fz_print_text(dev->ctx, stdout, text); printf("</fill_text>\n"); } @@ -158,7 +158,7 @@ fz_trace_stroke_text(fz_device *dev, fz_text *text, fz_stroke_state *stroke, fz_ fz_trace_matrix(ctm); fz_trace_trm(text->trm); printf(">\n"); - fz_debug_text(dev->ctx, text, 0); + fz_print_text(dev->ctx, stdout, text); printf("</stroke_text>\n"); } @@ -170,7 +170,7 @@ fz_trace_clip_text(fz_device *dev, fz_text *text, fz_matrix ctm, int accumulate) fz_trace_matrix(ctm); fz_trace_trm(text->trm); printf(">\n"); - fz_debug_text(dev->ctx, text, 0); + fz_print_text(dev->ctx, stdout, text); printf("</clip_text>\n"); } @@ -181,7 +181,7 @@ fz_trace_clip_stroke_text(fz_device *dev, fz_text *text, fz_stroke_state *stroke fz_trace_matrix(ctm); fz_trace_trm(text->trm); printf(">\n"); - fz_debug_text(dev->ctx, text, 0); + fz_print_text(dev->ctx, stdout, text); printf("</clip_stroke_text>\n"); } @@ -192,12 +192,12 @@ fz_trace_ignore_text(fz_device *dev, fz_text *text, fz_matrix ctm) fz_trace_matrix(ctm); fz_trace_trm(text->trm); printf(">\n"); - fz_debug_text(dev->ctx, text, 0); + fz_print_text(dev->ctx, stdout, text); printf("</ignore_text>\n"); } static void -fz_trace_fill_image(fz_device *dev, fz_pixmap *image, fz_matrix ctm, float alpha) +fz_trace_fill_image(fz_device *dev, fz_image *image, fz_matrix ctm, float alpha) { printf("<fill_image alpha=\"%g\" ", alpha); fz_trace_matrix(ctm); @@ -213,7 +213,7 @@ fz_trace_fill_shade(fz_device *dev, fz_shade *shade, fz_matrix ctm, float alpha) } static void -fz_trace_fill_image_mask(fz_device *dev, fz_pixmap *image, fz_matrix ctm, +fz_trace_fill_image_mask(fz_device *dev, fz_image *image, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha) { printf("<fill_image_mask "); @@ -223,7 +223,7 @@ fz_colorspace *colorspace, float *color, float alpha) } static void -fz_trace_clip_image_mask(fz_device *dev, fz_pixmap *image, fz_rect *rect, fz_matrix ctm) +fz_trace_clip_image_mask(fz_device *dev, fz_image *image, fz_rect *rect, fz_matrix ctm) { printf("<clip_image_mask "); fz_trace_matrix(ctm); diff --git a/fitz/doc_document.c b/fitz/doc_document.c index ca13af72..2da7a110 100644 --- a/fitz/doc_document.c +++ b/fitz/doc_document.c @@ -1,4 +1,4 @@ -#include "fitz.h" +#include "fitz-internal.h" /* Yuck! Promiscuous we are. */ extern struct pdf_document *pdf_open_document(fz_context *ctx, char *filename); diff --git a/fitz/doc_link.c b/fitz/doc_link.c index 71f5dfbf..d558d18a 100644 --- a/fitz/doc_link.c +++ b/fitz/doc_link.c @@ -1,4 +1,4 @@ -#include "fitz.h" +#include "fitz-internal.h" void fz_free_link_dest(fz_context *ctx, fz_link_dest *dest) diff --git a/fitz/doc_outline.c b/fitz/doc_outline.c index b69debaf..71694851 100644 --- a/fitz/doc_outline.c +++ b/fitz/doc_outline.c @@ -1,4 +1,4 @@ -#include "fitz.h" +#include "fitz-internal.h" void fz_free_outline(fz_context *ctx, fz_outline *outline) @@ -14,37 +14,49 @@ fz_free_outline(fz_context *ctx, fz_outline *outline) } } -void -fz_debug_outline_xml(fz_context *ctx, fz_outline *outline, int level) +static void +do_debug_outline_xml(FILE *out, fz_outline *outline, int level) { while (outline) { - printf("<outline title=\"%s\" page=\"%d\"", outline->title, outline->dest.kind == FZ_LINK_GOTO ? outline->dest.ld.gotor.page + 1 : 0); + fprintf(out, "<outline title=\"%s\" page=\"%d\"", outline->title, outline->dest.kind == FZ_LINK_GOTO ? outline->dest.ld.gotor.page + 1 : 0); if (outline->down) { - printf(">\n"); - fz_debug_outline_xml(ctx, outline->down, level + 1); - printf("</outline>\n"); + fprintf(out, ">\n"); + do_debug_outline_xml(out, outline->down, level + 1); + fprintf(out, "</outline>\n"); } else { - printf(" />\n"); + fprintf(out, " />\n"); } outline = outline->next; } } void -fz_debug_outline(fz_context *ctx, fz_outline *outline, int level) +fz_print_outline_xml(fz_context *ctx, FILE *out, fz_outline *outline) +{ + do_debug_outline_xml(out, outline, 0); +} + +static void +do_debug_outline(FILE *out, fz_outline *outline, int level) { int i; while (outline) { for (i = 0; i < level; i++) - putchar('\t'); - printf("%s\t%d\n", outline->title, outline->dest.kind == FZ_LINK_GOTO ? outline->dest.ld.gotor.page + 1 : 0); + fputc('\t', out); + fprintf(out, "%s\t%d\n", outline->title, outline->dest.kind == FZ_LINK_GOTO ? outline->dest.ld.gotor.page + 1 : 0); if (outline->down) - fz_debug_outline(ctx, outline->down, level + 1); + do_debug_outline(out, outline->down, level + 1); outline = outline->next; } } + +void +fz_print_outline(fz_context *ctx, FILE *out, fz_outline *outline) +{ + do_debug_outline(out, outline, 0); +} diff --git a/fitz/filt_basic.c b/fitz/filt_basic.c index ae239fed..09d63402 100644 --- a/fitz/filt_basic.c +++ b/fitz/filt_basic.c @@ -1,4 +1,4 @@ -#include "fitz.h" +#include "fitz-internal.h" /* Pretend we have a filter that just copies data forever */ diff --git a/fitz/filt_dctd.c b/fitz/filt_dctd.c index 4357f3d7..23744f01 100644 --- a/fitz/filt_dctd.c +++ b/fitz/filt_dctd.c @@ -1,4 +1,4 @@ -#include "fitz.h" +#include "fitz-internal.h" #include <jpeglib.h> #include <setjmp.h> @@ -12,6 +12,7 @@ struct fz_dctd_s int color_transform; int init; int stride; + int factor; unsigned char *scanline; unsigned char *rp, *wp; struct jpeg_decompress_struct cinfo; @@ -150,6 +151,9 @@ read_dctd(fz_stream *stm, unsigned char *buf, int len) break; } + cinfo->scale_num = 8/state->factor; + cinfo->scale_denom = 8; + jpeg_start_decompress(cinfo); state->stride = cinfo->output_width * cinfo->output_components; @@ -216,6 +220,12 @@ skip: fz_stream * fz_open_dctd(fz_stream *chain, int color_transform) { + return fz_open_resized_dctd(chain, color_transform, 1); +} + +fz_stream * +fz_open_resized_dctd(fz_stream *chain, int color_transform, int factor) +{ fz_context *ctx = chain->ctx; fz_dctd *state = NULL; @@ -228,6 +238,7 @@ fz_open_dctd(fz_stream *chain, int color_transform) state->chain = chain; state->color_transform = color_transform; state->init = 0; + state->factor = factor; } fz_catch(ctx) { diff --git a/fitz/filt_faxd.c b/fitz/filt_faxd.c index 4e522eb5..ada7e87b 100644 --- a/fitz/filt_faxd.c +++ b/fitz/filt_faxd.c @@ -1,4 +1,4 @@ -#include "fitz.h" +#include "fitz-internal.h" /* Fax G3/G4 decoder */ diff --git a/fitz/filt_flate.c b/fitz/filt_flate.c index 2eb0c563..24b6c081 100644 --- a/fitz/filt_flate.c +++ b/fitz/filt_flate.c @@ -1,4 +1,4 @@ -#include "fitz.h" +#include "fitz-internal.h" #include <zlib.h> diff --git a/fitz/filt_jbig2d.c b/fitz/filt_jbig2d.c index 3afcbcb0..415534c0 100644 --- a/fitz/filt_jbig2d.c +++ b/fitz/filt_jbig2d.c @@ -1,4 +1,4 @@ -#include "fitz.h" +#include "fitz-internal.h" #ifdef _WIN32 /* Microsoft Visual C++ */ diff --git a/fitz/filt_lzwd.c b/fitz/filt_lzwd.c index ac952ccf..3ee4d34c 100644 --- a/fitz/filt_lzwd.c +++ b/fitz/filt_lzwd.c @@ -1,4 +1,4 @@ -#include "fitz.h" +#include "fitz-internal.h" /* TODO: error checking */ diff --git a/fitz/filt_predict.c b/fitz/filt_predict.c index 8221c251..e68743d3 100644 --- a/fitz/filt_predict.c +++ b/fitz/filt_predict.c @@ -1,4 +1,4 @@ -#include "fitz.h" +#include "fitz-internal.h" /* TODO: check if this works with 16bpp images */ diff --git a/fitz/fitz-internal.h b/fitz/fitz-internal.h new file mode 100644 index 00000000..0a639b1c --- /dev/null +++ b/fitz/fitz-internal.h @@ -0,0 +1,1092 @@ +#ifndef FITZ_INTERNAL_H +#define FITZ_INTERNAL_H + +#include "fitz.h" + +struct fz_warn_context_s +{ + char message[256]; + int count; +}; + + +fz_context *fz_clone_context_internal(fz_context *ctx); + +void fz_new_aa_context(fz_context *ctx); +void fz_free_aa_context(fz_context *ctx); +void fz_copy_aa_context(fz_context *dst, fz_context *src); + +/* Default allocator */ +extern fz_alloc_context fz_alloc_default; + +/* Default locks */ +extern fz_locks_context fz_locks_default; + +#if defined(MEMENTO) || defined(DEBUG) +#define FITZ_DEBUG_LOCKING +#endif + +#ifdef FITZ_DEBUG_LOCKING + +void fz_assert_lock_held(fz_context *ctx, int lock); +void fz_assert_lock_not_held(fz_context *ctx, int lock); +void fz_lock_debug_lock(fz_context *ctx, int lock); +void fz_lock_debug_unlock(fz_context *ctx, int lock); + +#else + +#define fz_assert_lock_held(A,B) do { } while (0) +#define fz_assert_lock_not_held(A,B) do { } while (0) +#define fz_lock_debug_lock(A,B) do { } while (0) +#define fz_lock_debug_unlock(A,B) do { } while (0) + +#endif /* !FITZ_DEBUG_LOCKING */ + +static inline void +fz_lock(fz_context *ctx, int lock) +{ + fz_lock_debug_lock(ctx, lock); + ctx->locks->lock(ctx->locks->user, lock); +} + +static inline void +fz_unlock(fz_context *ctx, int lock) +{ + fz_lock_debug_unlock(ctx, lock); + ctx->locks->unlock(ctx->locks->user, lock); +} + + +/* + * Basic runtime and utility functions + */ + +/* + fz_malloc_struct: Allocate storage for a structure (with scavenging), + clear it, and (in Memento builds) tag the pointer as belonging to a + struct of this type. + + CTX: The context. + + STRUCT: The structure type. + + Returns a pointer to allocated (and cleared) structure. Throws + exception on failure to allocate. +*/ +/* alloc and zero a struct, and tag it for memento */ +#define fz_malloc_struct(CTX, STRUCT) \ + Memento_label(fz_calloc(CTX,1,sizeof(STRUCT)), #STRUCT) + +/* Range checking atof */ +float fz_atof(const char *s); + +/* + * Generic hash-table with fixed-length keys. + */ + +typedef struct fz_hash_table_s fz_hash_table; + +fz_hash_table *fz_new_hash_table(fz_context *ctx, int initialsize, int keylen, int lock); +void fz_print_hash(fz_context *ctx, FILE *out, fz_hash_table *table); +void fz_empty_hash(fz_context *ctx, fz_hash_table *table); +void fz_free_hash(fz_context *ctx, fz_hash_table *table); + +void *fz_hash_find(fz_context *ctx, fz_hash_table *table, void *key); +void *fz_hash_insert(fz_context *ctx, fz_hash_table *table, void *key, void *val); +void fz_hash_remove(fz_context *ctx, fz_hash_table *table, void *key); + +int fz_hash_len(fz_context *ctx, fz_hash_table *table); +void *fz_hash_get_key(fz_context *ctx, fz_hash_table *table, int idx); +void *fz_hash_get_val(fz_context *ctx, fz_hash_table *table, int idx); + +/* + * Math and geometry + */ + +/* Multiply scaled two integers in the 0..255 range */ +static inline int fz_mul255(int a, int b) +{ + /* see Jim Blinn's book "Dirty Pixels" for how this works */ + int x = a * b + 128; + x += x >> 8; + return x >> 8; +} + +/* Expand a value A from the 0...255 range to the 0..256 range */ +#define FZ_EXPAND(A) ((A)+((A)>>7)) + +/* Combine values A (in any range) and B (in the 0..256 range), + * to give a single value in the same range as A was. */ +#define FZ_COMBINE(A,B) (((A)*(B))>>8) + +/* Combine values A and C (in the same (any) range) and B and D (in the + * 0..256 range), to give a single value in the same range as A and C were. */ +#define FZ_COMBINE2(A,B,C,D) (FZ_COMBINE((A), (B)) + FZ_COMBINE((C), (D))) + +/* Blend SRC and DST (in the same range) together according to + * AMOUNT (in the 0...256 range). */ +#define FZ_BLEND(SRC, DST, AMOUNT) ((((SRC)-(DST))*(AMOUNT) + ((DST)<<8))>>8) + +void fz_gridfit_matrix(fz_matrix *m); +float fz_matrix_max_expansion(fz_matrix m); + +/* + * Basic crypto functions. + * Independent of the rest of fitz. + * For further encapsulation in filters, or not. + */ + +/* md5 digests */ + +typedef struct fz_md5_s fz_md5; + +struct fz_md5_s +{ + unsigned int state[4]; + unsigned int count[2]; + unsigned char buffer[64]; +}; + +void fz_md5_init(fz_md5 *state); +void fz_md5_update(fz_md5 *state, const unsigned char *input, unsigned inlen); +void fz_md5_final(fz_md5 *state, unsigned char digest[16]); + +/* sha-256 digests */ + +typedef struct fz_sha256_s fz_sha256; + +struct fz_sha256_s +{ + unsigned int state[8]; + unsigned int count[2]; + union { + unsigned char u8[64]; + unsigned int u32[16]; + } buffer; +}; + +void fz_sha256_init(fz_sha256 *state); +void fz_sha256_update(fz_sha256 *state, const unsigned char *input, unsigned int inlen); +void fz_sha256_final(fz_sha256 *state, unsigned char digest[32]); + +/* arc4 crypto */ + +typedef struct fz_arc4_s fz_arc4; + +struct fz_arc4_s +{ + unsigned x; + unsigned y; + unsigned char state[256]; +}; + +void fz_arc4_init(fz_arc4 *state, const unsigned char *key, unsigned len); +void fz_arc4_encrypt(fz_arc4 *state, unsigned char *dest, const unsigned char *src, unsigned len); + +/* AES block cipher implementation from XYSSL */ + +typedef struct fz_aes_s fz_aes; + +#define AES_DECRYPT 0 +#define AES_ENCRYPT 1 + +struct fz_aes_s +{ + int nr; /* number of rounds */ + unsigned long *rk; /* AES round keys */ + unsigned long buf[68]; /* unaligned data */ +}; + +void aes_setkey_enc( fz_aes *ctx, const unsigned char *key, int keysize ); +void aes_setkey_dec( fz_aes *ctx, const unsigned char *key, int keysize ); +void aes_crypt_cbc( fz_aes *ctx, int mode, int length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); + +/* + Resource store + + MuPDF stores decoded "objects" into a store for potential reuse. + If the size of the store gets too big, objects stored within it can + be evicted and freed to recover space. When MuPDF comes to decode + such an object, it will check to see if a version of this object is + already in the store - if it is, it will simply reuse it. If not, it + will decode it and place it into the store. + + All objects that can be placed into the store are derived from the + fz_storable type (i.e. this should be the first component of the + objects structure). This allows for consistent (thread safe) + reference counting, and includes a function that will be called to + free the object as soon as the reference count reaches zero. + + Most objects offer fz_keep_XXXX/fz_drop_XXXX functions derived + from fz_keep_storable/fz_drop_storable. Creation of such objects + includes a call to FZ_INIT_STORABLE to set up the fz_storable header. + */ + +typedef struct fz_storable_s fz_storable; + +typedef void (fz_store_free_fn)(fz_context *, fz_storable *); + +struct fz_storable_s { + int refs; + fz_store_free_fn *free; +}; + +#define FZ_INIT_STORABLE(S_,RC,FREE) \ + do { fz_storable *S = &(S_)->storable; S->refs = (RC); \ + S->free = (FREE); \ + } while (0) + +void *fz_keep_storable(fz_context *, fz_storable *); +void fz_drop_storable(fz_context *, fz_storable *); + +/* + The store can be seen as a dictionary that maps keys to fz_storable + values. In order to allow keys of different types to be stored, we + have a structure full of functions for each key 'type'; this + fz_store_type pointer is stored with each key, and tells the store + how to perform certain operations (like taking/dropping a reference, + comparing two keys, outputting details for debugging etc). + + The store uses a hash table internally for speed where possible. In + order for this to work, we need a mechanism for turning a generic + 'key' into 'a hashable string'. For this purpose the type structure + contains a make_hash_key function pointer that maps from a void * + to an fz_store_hash structure. If make_hash_key function returns 0, + then the key is determined not to be hashable, and the value is + not stored in the hash table. +*/ +typedef struct fz_store_hash_s fz_store_hash; + +struct fz_store_hash_s +{ + fz_store_free_fn *free; + union + { + struct + { + int i0; + int i1; + } i; + struct + { + void *ptr; + int i; + } pi; + } u; +}; + +typedef struct fz_store_type_s fz_store_type; + +struct fz_store_type_s +{ + int (*make_hash_key)(fz_store_hash *, void *); + void *(*keep_key)(fz_context *,void *); + void (*drop_key)(fz_context *,void *); + int (*cmp_key)(void *, void *); + void (*debug)(void *); +}; + +/* + fz_store_new_context: Create a new store inside the context + + max: The maximum size (in bytes) that the store is allowed to grow + to. FZ_STORE_UNLIMITED means no limit. +*/ +void fz_new_store_context(fz_context *ctx, unsigned int max); + +/* + fz_drop_store_context: Drop a reference to the store. +*/ +void fz_drop_store_context(fz_context *ctx); + +/* + fz_keep_store_context: Take a reference to the store. +*/ +fz_store *fz_keep_store_context(fz_context *ctx); + +/* + fz_print_store: Dump the contents of the store for debugging. +*/ +void fz_print_store(fz_context *ctx, FILE *out); + +/* + fz_store_item: Add an item to the store. + + Add an item into the store, returning NULL for success. If an item + with the same key is found in the store, then our item will not be + inserted, and the function will return a pointer to that value + instead. This function takes its own reference to val, as required + (i.e. the caller maintains ownership of its own reference). + + key: The key to use to index the item. + + val: The value to store. + + itemsize: The size in bytes of the value (as counted towards the + store size). + + type: Functions used to manipulate the key. +*/ +void *fz_store_item(fz_context *ctx, void *key, void *val, unsigned int itemsize, fz_store_type *type); + +/* + fz_find_item: Find an item within the store. + + free: The function used to free the value (to ensure we get a value + of the correct type). + + key: The key to use to index the item. + + type: Functions used to manipulate the key. + + Returns NULL for not found, otherwise returns a pointer to the value + indexed by key to which a reference has been taken. +*/ +void *fz_find_item(fz_context *ctx, fz_store_free_fn *free, void *key, fz_store_type *type); + +/* + fz_remove_item: Remove an item from the store. + + If an item indexed by the given key exists in the store, remove it. + + free: The function used to free the value (to ensure we get a value + of the correct type). + + key: The key to use to find the item to remove. + + type: Functions used to manipulate the key. +*/ +void fz_remove_item(fz_context *ctx, fz_store_free_fn *free, void *key, fz_store_type *type); + +/* + fz_empty_store: Evict everything from the store. +*/ +void fz_empty_store(fz_context *ctx); + +/* + fz_store_scavenge: Internal function used as part of the scavenging + allocator; when we fail to allocate memory, before returning a + failure to the caller, we try to scavenge space within the store by + evicting at least 'size' bytes. The allocator then retries. + + size: The number of bytes we are trying to have free. + + phase: What phase of the scavenge we are in. Updated on exit. + + Returns non zero if we managed to free any memory. +*/ +int fz_store_scavenge(fz_context *ctx, unsigned int size, int *phase); + +struct fz_buffer_s +{ + int refs; + unsigned char *data; + int cap, len; +}; + +/* + fz_new_buffer: Create a new buffer. + + capacity: Initial capacity. + + Returns pointer to new buffer. Throws exception on allocation + failure. +*/ +fz_buffer *fz_new_buffer(fz_context *ctx, int capacity); + +/* + fz_resize_buffer: Ensure that a buffer has a given capacity, + truncating data if required. + + buf: The buffer to alter. + + capacity: The desired capacity for the buffer. If the current size + of the buffer contents is smaller than capacity, it is truncated. + +*/ +void fz_resize_buffer(fz_context *ctx, fz_buffer *buf, int capacity); + +/* + fz_grow_buffer: Make some space within a buffer (i.e. ensure that + capacity > size). + + buf: The buffer to grow. + + May throw exception on failure to allocate. +*/ +void fz_grow_buffer(fz_context *ctx, fz_buffer *buf); + +/* + fz_trim_buffer: Trim wasted capacity from a buffer. + + buf: The buffer to trim. +*/ +void fz_trim_buffer(fz_context *ctx, fz_buffer *buf); + +struct fz_stream_s +{ + fz_context *ctx; + int refs; + int error; + int eof; + int pos; + int avail; + int bits; + int locked; + unsigned char *bp, *rp, *wp, *ep; + void *state; + int (*read)(fz_stream *stm, unsigned char *buf, int len); + void (*close)(fz_context *ctx, void *state); + void (*seek)(fz_stream *stm, int offset, int whence); + unsigned char buf[4096]; +}; + +void fz_lock_stream(fz_stream *stm); + +fz_stream *fz_new_stream(fz_context *ctx, void*, int(*)(fz_stream*, unsigned char*, int), void(*)(fz_context *, void *)); +fz_stream *fz_keep_stream(fz_stream *stm); +void fz_fill_buffer(fz_stream *stm); + +void fz_read_line(fz_stream *stm, char *buf, int max); + +static inline int fz_read_byte(fz_stream *stm) +{ + if (stm->rp == stm->wp) + { + fz_fill_buffer(stm); + return stm->rp < stm->wp ? *stm->rp++ : EOF; + } + return *stm->rp++; +} + +static inline int fz_peek_byte(fz_stream *stm) +{ + if (stm->rp == stm->wp) + { + fz_fill_buffer(stm); + return stm->rp < stm->wp ? *stm->rp : EOF; + } + return *stm->rp; +} + +static inline void fz_unread_byte(fz_stream *stm) +{ + if (stm->rp > stm->bp) + stm->rp--; +} + +static inline int fz_is_eof(fz_stream *stm) +{ + if (stm->rp == stm->wp) + { + if (stm->eof) + return 1; + return fz_peek_byte(stm) == EOF; + } + return 0; +} + +static inline unsigned int fz_read_bits(fz_stream *stm, int n) +{ + unsigned int x; + + if (n <= stm->avail) + { + stm->avail -= n; + x = (stm->bits >> stm->avail) & ((1 << n) - 1); + } + else + { + x = stm->bits & ((1 << stm->avail) - 1); + n -= stm->avail; + stm->avail = 0; + + while (n > 8) + { + x = (x << 8) | fz_read_byte(stm); + n -= 8; + } + + if (n > 0) + { + stm->bits = fz_read_byte(stm); + stm->avail = 8 - n; + x = (x << n) | (stm->bits >> stm->avail); + } + } + + return x; +} + +static inline void fz_sync_bits(fz_stream *stm) +{ + stm->avail = 0; +} + +static inline int fz_is_eof_bits(fz_stream *stm) +{ + return fz_is_eof(stm) && (stm->avail == 0 || stm->bits == EOF); +} + +/* + * Data filters. + */ + +fz_stream *fz_open_copy(fz_stream *chain); +fz_stream *fz_open_null(fz_stream *chain, int len); +fz_stream *fz_open_arc4(fz_stream *chain, unsigned char *key, unsigned keylen); +fz_stream *fz_open_aesd(fz_stream *chain, unsigned char *key, unsigned keylen); +fz_stream *fz_open_a85d(fz_stream *chain); +fz_stream *fz_open_ahxd(fz_stream *chain); +fz_stream *fz_open_rld(fz_stream *chain); +fz_stream *fz_open_dctd(fz_stream *chain, int color_transform); +fz_stream *fz_open_resized_dctd(fz_stream *chain, int color_transform, int factor); +fz_stream *fz_open_faxd(fz_stream *chain, + int k, int end_of_line, int encoded_byte_align, + int columns, int rows, int end_of_block, int black_is_1); +fz_stream *fz_open_flated(fz_stream *chain); +fz_stream *fz_open_lzwd(fz_stream *chain, int early_change); +fz_stream *fz_open_predict(fz_stream *chain, int predictor, int columns, int colors, int bpc); +fz_stream *fz_open_jbig2d(fz_stream *chain, fz_buffer *global); + +/* + * Resources and other graphics related objects. + */ + +enum { FZ_MAX_COLORS = 32 }; + +int fz_lookup_blendmode(char *name); +char *fz_blendmode_name(int blendmode); + +struct fz_bitmap_s +{ + int refs; + int w, h, stride, n; + unsigned char *samples; +}; + +fz_bitmap *fz_new_bitmap(fz_context *ctx, int w, int h, int n); + +void fz_bitmap_details(fz_bitmap *bitmap, int *w, int *h, int *n, int *stride); + +void fz_clear_bitmap(fz_context *ctx, fz_bitmap *bit); + +/* + Pixmaps represent a set of pixels for a 2 dimensional region of a + plane. Each pixel has n components per pixel, the last of which is + always alpha. The data is in premultiplied alpha when rendering, but + non-premultiplied for colorspace conversions and rescaling. + + x, y: The minimum x and y coord of the region in pixels. + + w, h: The width and height of the region in pixels. + + n: The number of color components in the image. Always + includes a separate alpha channel. For mask images n=1, for greyscale + (plus alpha) images n=2, for rgb (plus alpha) images n=3. + + interpolate: A boolean flag set to non-zero if the image + will be drawn using linear interpolation, or set to zero if + image will be using nearest neighbour sampling. + + xres, yres: Image resolution in dpi. Default is 96 dpi. + + colorspace: Pointer to a colorspace object describing the colorspace + the pixmap is in. If NULL, the image is a mask. + + samples: A simple block of memory w * h * n bytes of memory in which + the components are stored. The first n bytes are components 0 to n-1 + for the pixel at (x,y). Each successive n bytes gives another pixel + in scanline order. Subsequent scanlines follow on with no padding. + + free_samples: Is zero when an application has provided its own + buffer for pixel data through fz_new_pixmap_with_bbox_and_data. + If not zero the buffer will be freed when fz_drop_pixmap is + called for the pixmap. +*/ +struct fz_pixmap_s +{ + fz_storable storable; + int x, y, w, h, n; + int interpolate; + int xres, yres; + fz_colorspace *colorspace; + unsigned char *samples; + int free_samples; +}; + +void fz_free_pixmap_imp(fz_context *ctx, fz_storable *pix); + +void fz_clear_pixmap_rect_with_value(fz_context *ctx, fz_pixmap *pix, int value, fz_bbox r); +void fz_copy_pixmap_rect(fz_context *ctx, fz_pixmap *dest, fz_pixmap *src, fz_bbox r); +void fz_premultiply_pixmap(fz_context *ctx, fz_pixmap *pix); +fz_pixmap *fz_alpha_from_gray(fz_context *ctx, fz_pixmap *gray, int luminosity); +unsigned int fz_pixmap_size(fz_context *ctx, fz_pixmap *pix); + +fz_pixmap *fz_scale_pixmap(fz_context *ctx, fz_pixmap *src, float x, float y, float w, float h, fz_bbox *clip); + +fz_bbox fz_pixmap_bbox_no_ctx(fz_pixmap *src); + +struct fz_image_s +{ + fz_storable storable; + int w, h; + fz_image *mask; + fz_colorspace *colorspace; + fz_pixmap *(*get_pixmap)(fz_context *, fz_image *, int w, int h); +}; + +fz_pixmap *fz_load_jpx(fz_context *ctx, unsigned char *data, int size, fz_colorspace *cs); +fz_pixmap *fz_load_jpeg(fz_context *doc, unsigned char *data, int size); +fz_pixmap *fz_load_png(fz_context *doc, unsigned char *data, int size); +fz_pixmap *fz_load_tiff(fz_context *doc, unsigned char *data, int size); + +struct fz_halftone_s +{ + int refs; + int n; + fz_pixmap *comp[1]; +}; + +fz_halftone *fz_new_halftone(fz_context *ctx, int num_comps); +fz_halftone *fz_default_halftone(fz_context *ctx, int num_comps); +void fz_drop_halftone(fz_context *ctx, fz_halftone *half); +fz_halftone *fz_keep_halftone(fz_context *ctx, fz_halftone *half); + +struct fz_colorspace_s +{ + fz_storable storable; + unsigned int size; + char name[16]; + int n; + void (*to_rgb)(fz_context *ctx, fz_colorspace *, float *src, float *rgb); + void (*from_rgb)(fz_context *ctx, fz_colorspace *, float *rgb, float *dst); + void (*free_data)(fz_context *Ctx, fz_colorspace *); + void *data; +}; + +fz_colorspace *fz_new_colorspace(fz_context *ctx, char *name, int n); +fz_colorspace *fz_keep_colorspace(fz_context *ctx, fz_colorspace *colorspace); +void fz_drop_colorspace(fz_context *ctx, fz_colorspace *colorspace); +void fz_free_colorspace_imp(fz_context *ctx, fz_storable *colorspace); + +void fz_convert_color(fz_context *ctx, fz_colorspace *dsts, float *dstv, fz_colorspace *srcs, float *srcv); + +/* + * Fonts come in two variants: + * Regular fonts are handled by FreeType. + * Type 3 fonts have callbacks to the interpreter. + */ + +char *ft_error_string(int err); + +struct fz_font_s +{ + int refs; + char name[32]; + + void *ft_face; /* has an FT_Face if used */ + int ft_substitute; /* ... substitute metrics */ + int ft_bold; /* ... synthesize bold */ + int ft_italic; /* ... synthesize italic */ + int ft_hint; /* ... force hinting for DynaLab fonts */ + + /* origin of font data */ + char *ft_file; + unsigned char *ft_data; + int ft_size; + + fz_matrix t3matrix; + void *t3resources; + fz_buffer **t3procs; /* has 256 entries if used */ + float *t3widths; /* has 256 entries if used */ + char *t3flags; /* has 256 entries if used */ + void *t3doc; /* a pdf_document for the callback */ + void (*t3run)(void *doc, void *resources, fz_buffer *contents, fz_device *dev, fz_matrix ctm, void *gstate); + void (*t3freeres)(void *doc, void *resources); + + fz_rect bbox; /* font bbox is used only for t3 fonts */ + + /* per glyph bounding box cache */ + int use_glyph_bbox; + int bbox_count; + fz_rect *bbox_table; + + /* substitute metrics */ + int width_count; + int *width_table; /* in 1000 units */ +}; + +void fz_new_font_context(fz_context *ctx); +fz_font_context *fz_keep_font_context(fz_context *ctx); +void fz_drop_font_context(fz_context *ctx); + +fz_font *fz_new_type3_font(fz_context *ctx, char *name, fz_matrix matrix); + +fz_font *fz_new_font_from_memory(fz_context *ctx, unsigned char *data, int len, int index, int use_glyph_bbox); +fz_font *fz_new_font_from_file(fz_context *ctx, char *path, int index, int use_glyph_bbox); + +fz_font *fz_keep_font(fz_context *ctx, fz_font *font); +void fz_drop_font(fz_context *ctx, fz_font *font); + +void fz_print_font(fz_context *ctx, FILE *out, fz_font *font); + +void fz_set_font_bbox(fz_context *ctx, fz_font *font, float xmin, float ymin, float xmax, float ymax); +fz_rect fz_bound_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm); +int fz_glyph_cacheable(fz_context *ctx, fz_font *font, int gid); + +/* + * Vector path buffer. + * It can be stroked and dashed, or be filled. + * It has a fill rule (nonzero or even_odd). + * + * When rendering, they are flattened, stroked and dashed straight + * into the Global Edge List. + */ + +typedef struct fz_path_s fz_path; +typedef struct fz_stroke_state_s fz_stroke_state; + +typedef union fz_path_item_s fz_path_item; + +typedef enum fz_path_item_kind_e +{ + FZ_MOVETO, + FZ_LINETO, + FZ_CURVETO, + FZ_CLOSE_PATH +} fz_path_item_kind; + +typedef enum fz_linecap_e +{ + FZ_LINECAP_BUTT = 0, + FZ_LINECAP_ROUND = 1, + FZ_LINECAP_SQUARE = 2, + FZ_LINECAP_TRIANGLE = 3 +} fz_linecap; + +typedef enum fz_linejoin_e +{ + FZ_LINEJOIN_MITER = 0, + FZ_LINEJOIN_ROUND = 1, + FZ_LINEJOIN_BEVEL = 2, + FZ_LINEJOIN_MITER_XPS = 3 +} fz_linejoin; + +union fz_path_item_s +{ + fz_path_item_kind k; + float v; +}; + +struct fz_path_s +{ + int len, cap; + fz_path_item *items; + int last; +}; + +struct fz_stroke_state_s +{ + fz_linecap start_cap, dash_cap, end_cap; + fz_linejoin linejoin; + float linewidth; + float miterlimit; + float dash_phase; + int dash_len; + float dash_list[32]; +}; + +fz_path *fz_new_path(fz_context *ctx); +void fz_moveto(fz_context*, fz_path*, float x, float y); +void fz_lineto(fz_context*, fz_path*, float x, float y); +void fz_curveto(fz_context*,fz_path*, float, float, float, float, float, float); +void fz_curvetov(fz_context*,fz_path*, float, float, float, float); +void fz_curvetoy(fz_context*,fz_path*, float, float, float, float); +void fz_closepath(fz_context*,fz_path*); +void fz_free_path(fz_context *ctx, fz_path *path); + +void fz_transform_path(fz_context *ctx, fz_path *path, fz_matrix transform); + +fz_path *fz_clone_path(fz_context *ctx, fz_path *old); + +fz_rect fz_bound_path(fz_context *ctx, fz_path *path, fz_stroke_state *stroke, fz_matrix ctm); +void fz_print_path(fz_context *ctx, FILE *out, fz_path *, int indent); + +/* + * Glyph cache + */ + +void fz_new_glyph_cache_context(fz_context *ctx); +fz_glyph_cache *fz_keep_glyph_cache(fz_context *ctx); +void fz_drop_glyph_cache_context(fz_context *ctx); +void fz_purge_glyph_cache(fz_context *ctx); + +fz_pixmap *fz_render_ft_glyph(fz_context *ctx, fz_font *font, int cid, fz_matrix trm, int aa); +fz_pixmap *fz_render_t3_glyph(fz_context *ctx, fz_font *font, int cid, fz_matrix trm, fz_colorspace *model); +fz_pixmap *fz_render_ft_stroked_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm, fz_matrix ctm, fz_stroke_state *state); +fz_pixmap *fz_render_glyph(fz_context *ctx, fz_font*, int, fz_matrix, fz_colorspace *model); +fz_pixmap *fz_render_stroked_glyph(fz_context *ctx, fz_font*, int, fz_matrix, fz_matrix, fz_stroke_state *stroke); +void fz_render_t3_glyph_direct(fz_context *ctx, fz_device *dev, fz_font *font, int gid, fz_matrix trm, void *gstate); + +/* + * Text buffer. + * + * The trm field contains the a, b, c and d coefficients. + * The e and f coefficients come from the individual elements, + * together they form the transform matrix for the glyph. + * + * Glyphs are referenced by glyph ID. + * The Unicode text equivalent is kept in a separate array + * with indexes into the glyph array. + */ + +typedef struct fz_text_s fz_text; +typedef struct fz_text_item_s fz_text_item; + +struct fz_text_item_s +{ + float x, y; + int gid; /* -1 for one gid to many ucs mappings */ + int ucs; /* -1 for one ucs to many gid mappings */ +}; + +struct fz_text_s +{ + fz_font *font; + fz_matrix trm; + int wmode; + int len, cap; + fz_text_item *items; +}; + +fz_text *fz_new_text(fz_context *ctx, fz_font *face, fz_matrix trm, int wmode); +void fz_add_text(fz_context *ctx, fz_text *text, int gid, int ucs, float x, float y); +void fz_free_text(fz_context *ctx, fz_text *text); +fz_rect fz_bound_text(fz_context *ctx, fz_text *text, fz_matrix ctm); +fz_text *fz_clone_text(fz_context *ctx, fz_text *old); +void fz_print_text(fz_context *ctx, FILE *out, fz_text*); + +/* + * The shading code uses gouraud shaded triangle meshes. + */ + +enum +{ + FZ_LINEAR, + FZ_RADIAL, + FZ_MESH, +}; + +typedef struct fz_shade_s fz_shade; + +struct fz_shade_s +{ + fz_storable storable; + + fz_rect bbox; /* can be fz_infinite_rect */ + fz_colorspace *colorspace; + + fz_matrix matrix; /* matrix from pattern dict */ + int use_background; /* background color for fills but not 'sh' */ + float background[FZ_MAX_COLORS]; + + int use_function; + float function[256][FZ_MAX_COLORS + 1]; + + int type; /* linear, radial, mesh */ + int extend[2]; + + int mesh_len; + int mesh_cap; + float *mesh; /* [x y 0], [x y r], [x y t] or [x y c1 ... cn] */ +}; + +fz_shade *fz_keep_shade(fz_context *ctx, fz_shade *shade); +void fz_drop_shade(fz_context *ctx, fz_shade *shade); +void fz_free_shade_imp(fz_context *ctx, fz_storable *shade); +void fz_print_shade(fz_context *ctx, FILE *out, fz_shade *shade); + +fz_rect fz_bound_shade(fz_context *ctx, fz_shade *shade, fz_matrix ctm); +void fz_paint_shade(fz_context *ctx, fz_shade *shade, fz_matrix ctm, fz_pixmap *dest, fz_bbox bbox); + +/* + * Scan converter + */ + +typedef struct fz_gel_s fz_gel; + +fz_gel *fz_new_gel(fz_context *ctx); +void fz_insert_gel(fz_gel *gel, float x0, float y0, float x1, float y1); +void fz_reset_gel(fz_gel *gel, fz_bbox clip); +void fz_sort_gel(fz_gel *gel); +fz_bbox fz_bound_gel(fz_gel *gel); +void fz_free_gel(fz_gel *gel); +int fz_is_rect_gel(fz_gel *gel); + +void fz_scan_convert(fz_gel *gel, int eofill, fz_bbox clip, fz_pixmap *pix, unsigned char *colorbv); + +void fz_flatten_fill_path(fz_gel *gel, fz_path *path, fz_matrix ctm, float flatness); +void fz_flatten_stroke_path(fz_gel *gel, fz_path *path, fz_stroke_state *stroke, fz_matrix ctm, float flatness, float linewidth); +void fz_flatten_dash_path(fz_gel *gel, fz_path *path, fz_stroke_state *stroke, fz_matrix ctm, float flatness, float linewidth); + +/* + * The device interface. + */ + +fz_device *fz_new_draw_device_type3(fz_context *ctx, fz_pixmap *dest); + +enum +{ + /* Hints */ + FZ_IGNORE_IMAGE = 1, + FZ_IGNORE_SHADE = 2, + + /* Flags */ + FZ_DEVFLAG_MASK = 1, + FZ_DEVFLAG_COLOR = 2, + FZ_DEVFLAG_UNCACHEABLE = 4, + FZ_DEVFLAG_FILLCOLOR_UNDEFINED = 8, + FZ_DEVFLAG_STROKECOLOR_UNDEFINED = 16, + FZ_DEVFLAG_STARTCAP_UNDEFINED = 32, + FZ_DEVFLAG_DASHCAP_UNDEFINED = 64, + FZ_DEVFLAG_ENDCAP_UNDEFINED = 128, + FZ_DEVFLAG_LINEJOIN_UNDEFINED = 256, + FZ_DEVFLAG_MITERLIMIT_UNDEFINED = 512, + FZ_DEVFLAG_LINEWIDTH_UNDEFINED = 1024, + /* Arguably we should have a bit for the dash pattern itself being + * undefined, but that causes problems; do we assume that it should + * always be set to non-dashing at the start of every glyph? */ +}; + +struct fz_device_s +{ + int hints; + int flags; + + void *user; + void (*free_user)(fz_device *); + fz_context *ctx; + + void (*fill_path)(fz_device *, fz_path *, int even_odd, fz_matrix, fz_colorspace *, float *color, float alpha); + void (*stroke_path)(fz_device *, fz_path *, fz_stroke_state *, fz_matrix, fz_colorspace *, float *color, float alpha); + void (*clip_path)(fz_device *, fz_path *, fz_rect *rect, int even_odd, fz_matrix); + void (*clip_stroke_path)(fz_device *, fz_path *, fz_rect *rect, fz_stroke_state *, fz_matrix); + + void (*fill_text)(fz_device *, fz_text *, fz_matrix, fz_colorspace *, float *color, float alpha); + void (*stroke_text)(fz_device *, fz_text *, fz_stroke_state *, fz_matrix, fz_colorspace *, float *color, float alpha); + void (*clip_text)(fz_device *, fz_text *, fz_matrix, int accumulate); + void (*clip_stroke_text)(fz_device *, fz_text *, fz_stroke_state *, fz_matrix); + void (*ignore_text)(fz_device *, fz_text *, fz_matrix); + + void (*fill_shade)(fz_device *, fz_shade *shd, fz_matrix ctm, float alpha); + void (*fill_image)(fz_device *, fz_image *img, fz_matrix ctm, float alpha); + void (*fill_image_mask)(fz_device *, fz_image *img, fz_matrix ctm, fz_colorspace *, float *color, float alpha); + void (*clip_image_mask)(fz_device *, fz_image *img, fz_rect *rect, fz_matrix ctm); + + void (*pop_clip)(fz_device *); + + void (*begin_mask)(fz_device *, fz_rect, int luminosity, fz_colorspace *, float *bc); + void (*end_mask)(fz_device *); + void (*begin_group)(fz_device *, fz_rect, int isolated, int knockout, int blendmode, float alpha); + void (*end_group)(fz_device *); + + void (*begin_tile)(fz_device *, fz_rect area, fz_rect view, float xstep, float ystep, fz_matrix ctm); + void (*end_tile)(fz_device *); +}; + +void fz_fill_path(fz_device *dev, fz_path *path, int even_odd, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha); +void fz_stroke_path(fz_device *dev, fz_path *path, fz_stroke_state *stroke, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha); +void fz_clip_path(fz_device *dev, fz_path *path, fz_rect *rect, int even_odd, fz_matrix ctm); +void fz_clip_stroke_path(fz_device *dev, fz_path *path, fz_rect *rect, fz_stroke_state *stroke, fz_matrix ctm); +void fz_fill_text(fz_device *dev, fz_text *text, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha); +void fz_stroke_text(fz_device *dev, fz_text *text, fz_stroke_state *stroke, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha); +void fz_clip_text(fz_device *dev, fz_text *text, fz_matrix ctm, int accumulate); +void fz_clip_stroke_text(fz_device *dev, fz_text *text, fz_stroke_state *stroke, fz_matrix ctm); +void fz_ignore_text(fz_device *dev, fz_text *text, fz_matrix ctm); +void fz_pop_clip(fz_device *dev); +void fz_fill_shade(fz_device *dev, fz_shade *shade, fz_matrix ctm, float alpha); +void fz_fill_image(fz_device *dev, fz_image *image, fz_matrix ctm, float alpha); +void fz_fill_image_mask(fz_device *dev, fz_image *image, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha); +void fz_clip_image_mask(fz_device *dev, fz_image *image, fz_rect *rect, fz_matrix ctm); +void fz_begin_mask(fz_device *dev, fz_rect area, int luminosity, fz_colorspace *colorspace, float *bc); +void fz_end_mask(fz_device *dev); +void fz_begin_group(fz_device *dev, fz_rect area, int isolated, int knockout, int blendmode, float alpha); +void fz_end_group(fz_device *dev); +void fz_begin_tile(fz_device *dev, fz_rect area, fz_rect view, float xstep, float ystep, fz_matrix ctm); +void fz_end_tile(fz_device *dev); + +fz_device *fz_new_device(fz_context *ctx, void *user); + + + +/* + * Plotting functions. + */ + +void fz_decode_tile(fz_pixmap *pix, float *decode); +void fz_decode_indexed_tile(fz_pixmap *pix, float *decode, int maxval); +void fz_unpack_tile(fz_pixmap *dst, unsigned char * restrict src, int n, int depth, int stride, int scale); + +void fz_paint_solid_alpha(unsigned char * restrict dp, int w, int alpha); +void fz_paint_solid_color(unsigned char * restrict dp, int n, int w, unsigned char *color); + +void fz_paint_span(unsigned char * restrict dp, unsigned char * restrict sp, int n, int w, int alpha); +void fz_paint_span_with_color(unsigned char * restrict dp, unsigned char * restrict mp, int n, int w, unsigned char *color); + +void fz_paint_image(fz_pixmap *dst, fz_bbox scissor, fz_pixmap *shape, fz_pixmap *img, fz_matrix ctm, int alpha); +void fz_paint_image_with_color(fz_pixmap *dst, fz_bbox scissor, fz_pixmap *shape, fz_pixmap *img, fz_matrix ctm, unsigned char *colorbv); + +void fz_paint_pixmap(fz_pixmap *dst, fz_pixmap *src, int alpha); +void fz_paint_pixmap_with_mask(fz_pixmap *dst, fz_pixmap *src, fz_pixmap *msk); +void fz_paint_pixmap_with_rect(fz_pixmap *dst, fz_pixmap *src, int alpha, fz_bbox bbox); + +void fz_blend_pixmap(fz_pixmap *dst, fz_pixmap *src, int alpha, int blendmode, int isolated, fz_pixmap *shape); +void fz_blend_pixel(unsigned char dp[3], unsigned char bp[3], unsigned char sp[3], int blendmode); + +enum +{ + /* PDF 1.4 -- standard separable */ + FZ_BLEND_NORMAL, + FZ_BLEND_MULTIPLY, + FZ_BLEND_SCREEN, + FZ_BLEND_OVERLAY, + FZ_BLEND_DARKEN, + FZ_BLEND_LIGHTEN, + FZ_BLEND_COLOR_DODGE, + FZ_BLEND_COLOR_BURN, + FZ_BLEND_HARD_LIGHT, + FZ_BLEND_SOFT_LIGHT, + FZ_BLEND_DIFFERENCE, + FZ_BLEND_EXCLUSION, + + /* PDF 1.4 -- standard non-separable */ + FZ_BLEND_HUE, + FZ_BLEND_SATURATION, + FZ_BLEND_COLOR, + FZ_BLEND_LUMINOSITY, + + /* For packing purposes */ + FZ_BLEND_MODEMASK = 15, + FZ_BLEND_ISOLATED = 16, + FZ_BLEND_KNOCKOUT = 32 +}; + +struct fz_document_s +{ + void (*close)(fz_document *); + int (*needs_password)(fz_document *doc); + int (*authenticate_password)(fz_document *doc, char *password); + fz_outline *(*load_outline)(fz_document *doc); + int (*count_pages)(fz_document *doc); + fz_page *(*load_page)(fz_document *doc, int number); + fz_link *(*load_links)(fz_document *doc, fz_page *page); + fz_rect (*bound_page)(fz_document *doc, fz_page *page); + void (*run_page)(fz_document *doc, fz_page *page, fz_device *dev, fz_matrix transform, fz_cookie *cookie); + void (*free_page)(fz_document *doc, fz_page *page); +}; + +#endif diff --git a/fitz/fitz.h b/fitz/fitz.h index d2672031..26751824 100644 --- a/fitz/fitz.h +++ b/fitz/fitz.h @@ -1,9 +1,9 @@ -#ifndef _FITZ_H_ -#define _FITZ_H_ +#ifndef FITZ_H +#define FITZ_H /* - * Include the standard libc headers. - */ + Include the standard libc headers. +*/ #include <stdio.h> #include <stdlib.h> @@ -15,13 +15,27 @@ #include <assert.h> #include <errno.h> #include <limits.h> /* INT_MAX & co */ -#include <float.h> /* FLT_EPSILON */ +#include <float.h> /* FLT_EPSILON, FLT_MAX & co */ #include <fcntl.h> /* O_RDONLY & co */ #include <setjmp.h> #include "memento.h" +/* + Some versions of setjmp/longjmp (notably MacOSX and ios) store/restore + signal handlers too. We don't alter signal handlers within mupdf, so + there is no need for us to store/restore - hence we use the + non-restoring variants. This makes a large speed difference. +*/ +#ifdef __APPLE__ +#define fz_setjmp _setjmp +#define fz_longjmp _longjmp +#else +#define fz_setjmp setjmp +#define fz_longjmp longjmp +#endif + #ifdef __ANDROID__ #include <android/log.h> #define LOG_TAG "libmupdf" @@ -38,10 +52,11 @@ #define MIN(a,b) ( (a) < (b) ? (a) : (b) ) #define MAX(a,b) ( (a) > (b) ? (a) : (b) ) #define CLAMP(x,a,b) ( (x) > (b) ? (b) : ( (x) < (a) ? (a) : (x) ) ) +#define DIV_BY_ZERO(a, b, min, max) (((a) < 0) ^ ((b) < 0) ? (min) : (max)) /* - * Some differences in libc can be smoothed over - */ + Some differences in libc can be smoothed over +*/ #ifdef _MSC_VER /* Microsoft Visual C */ @@ -54,7 +69,7 @@ int gettimeofday(struct timeval *tv, struct timezone *tz); #define snprintf _snprintf -#define strtoll _strtoi64 +#define isnan _isnan #else /* Unix or close enough */ @@ -75,8 +90,8 @@ int gettimeofday(struct timeval *tv, struct timezone *tz); #endif /* - * Variadic macros, inline and restrict keywords - */ + Variadic macros, inline and restrict keywords +*/ #if __STDC_VERSION__ == 199901L /* C99 */ #elif _MSC_VER >= 1500 /* MSVC 9 or newer */ @@ -91,8 +106,8 @@ int gettimeofday(struct timeval *tv, struct timezone *tz); #endif /* - * GCC can do type checking of printf strings - */ + GCC can do type checking of printf strings +*/ #ifndef __printflike #if __GNUC__ > 2 || __GNUC__ == 2 && __GNUC_MINOR__ >= 7 @@ -103,7 +118,9 @@ int gettimeofday(struct timeval *tv, struct timezone *tz); #endif #endif -/* Contexts */ +/* + Contexts +*/ typedef struct fz_alloc_context_s fz_alloc_context; typedef struct fz_error_context_s fz_error_context; @@ -123,9 +140,6 @@ struct fz_alloc_context_s void (*free)(void *, void *); }; -/* Default allocator */ -extern fz_alloc_context fz_alloc_default; - struct fz_error_context_s { int top; @@ -140,139 +154,13 @@ void fz_var_imp(void *); #define fz_var(var) fz_var_imp((void *)&(var)) /* - -MuPDF uses a set of exception handling macros to simplify error return -and cleanup. Conceptually, they work a lot like C++'s try/catch system, -but do not require any special compiler support. - -The basic formulation is as follows: - - fz_try(ctx) - { - // Try to perform a task. Never 'return', 'goto' or 'longjmp' out - // of here. 'break' may be used to safely exit (just) the try block - // scope. - } - fz_always(ctx) - { - // Any code here is always executed, regardless of whether an - // exception was thrown within the try or not. Never 'return', 'goto' - // or longjmp out from here. 'break' may be used to safely exit (just) - // the always block scope. - } - fz_catch(ctx) - { - // This code is called (after any always block) only if something - // within the fz_try block (including any functions it called) threw - // an exception. The code here is expected to handle the exception - // (maybe record/report the error, cleanup any stray state etc) and - // can then either exit the block, or pass on the exception to a - // higher level (enclosing) fz_try block (using fz_throw, or - // fz_rethrow). - } - -The fz_always block is optional, and can safely be omitted. - -The macro based nature of this system has 3 main limitations: - -1) Never return from within try (or 'goto' or longjmp out of it). - This upsets the internal housekeeping of the macros and will cause - problems later on. The code will detect such things happening, but - by then it is too late to give a helpful error report as to where the - original infraction occurred. - -2) The fz_try(ctx) { ... } fz_always(ctx) { ... } fz_catch(ctx) { ... } - is not one atomic C statement. That is to say, if you do: - - if (condition) - fz_try(ctx) { ... } - fz_catch(ctx) { ... } - - then you will not get what you want. Use the following instead: - - if (condition) { - fz_try(ctx) { ... } - fz_catch(ctx) { ... } - } - -3) The macros are implemented using setjmp and longjmp, and so the standard - C restrictions on the use of those functions apply to fz_try/fz_catch - too. In particular, any "truly local" variable that is set between the - start of fz_try and something in fz_try throwing an exception may become - undefined as part of the process of throwing that exception. - - As a way of mitigating this problem, we provide an fz_var() macro that - tells the compiler to ensure that that variable is not unset by the - act of throwing the exception. - -A model piece of code using these macros then might be: - - house build_house(plans *p) - { - material m = NULL; - walls w = NULL; - roof r = NULL; - house h = NULL; - tiles t = make_tiles(); - - fz_var(w); - fz_var(r); - fz_var(h); - - fz_try(ctx) - { - fz_try(ctx) - { - m = make_bricks(); - } - fz_catch(ctx) - { - // No bricks available, make do with straw? - m = make_straw(); - } - w = make_walls(m, p); - r = make_roof(m, t); - h = combine(w, r); // Note, NOT: return combine(w,r); - } - fz_always(ctx) - { - drop_walls(w); - drop_roof(r); - drop_material(m); - drop_tiles(t); - } - fz_catch(ctx) - { - fz_throw(ctx, "build_house failed"); - } - return h; - } - -Things to note about this: - -a) If make_tiles throws an exception, this will immediately be handled - by some higher level exception handler. If it succeeds, t will be - set before fz_try starts, so there is no need to fz_var(t); - -b) We try first off to make some bricks as our building material. If - this fails, we fall back to straw. If this fails, we'll end up in - the fz_catch, and the process will fail neatly. - -c) We assume in this code that combine takes new reference to both the - walls and the roof it uses, and therefore that w and r need to be - cleaned up in all cases. - -d) We assume the standard C convention that it is safe to destroy - NULL things. - + Exception macro definitions. Just treat these as a black box - pay no + attention to the man behind the curtain. */ -/* Exception macro definitions. Just treat these as a black box - pay no - * attention to the man behind the curtain. */ - #define fz_try(ctx) \ if (fz_push_try(ctx->error), \ - (ctx->error->stack[ctx->error->top].code = setjmp(ctx->error->stack[ctx->error->top].buffer)) == 0) \ + (ctx->error->stack[ctx->error->top].code = fz_setjmp(ctx->error->stack[ctx->error->top].buffer)) == 0) \ { do { #define fz_always(ctx) \ @@ -285,78 +173,22 @@ d) We assume the standard C convention that it is safe to destroy } \ if (ctx->error->stack[ctx->error->top--].code) -/* - -We also include a couple of other formulations of the macros, with -different strengths and weaknesses. These will be removed shortly, but -I want them in git for at least 1 revision so I have a record of them. - -A formulation of try/always/catch that lifts limitation 2 above, but -has problems when try/catch are nested in the same function; the inner -nestings need to use fz_always_(ctx, label) and fz_catch_(ctx, label) -instead. This was held as too high a price to pay to drop limitation 2. - -#define fz_try(ctx) \ - if (fz_push_try(ctx->error), \ - (ctx->error->stack[ctx->error->top].code = setjmp(ctx->error->stack[ctx->error->top].buffer)) == 0) \ - { do { - -#define fz_always_(ctx, label) \ - } while (0); \ - goto ALWAYS_LABEL_ ## label ; \ - } \ - else if (ctx->error->stack[ctx->error->top].code) \ - { ALWAYS_LABEL_ ## label : \ - do { - -#define fz_catch_(ctx, label) \ - } while(0); \ - if (ctx->error->stack[ctx->error->top--].code) \ - goto CATCH_LABEL_ ## label; \ - } \ - else if (ctx->error->top--, 1) \ - CATCH_LABEL ## label: - -#define fz_always(ctx) fz_always_(ctx, TOP) -#define fz_catch(ctx) fz_catch_(ctx, TOP) - -Another alternative formulation, that again removes limitation 2, but at -the cost of an always block always costing us 1 extra longjmp per -execution. Again this was felt to be too high a cost to use. - -#define fz_try(ctx) \ - if (fz_push_try(ctx->error), \ - (ctx->error->stack[ctx->error->top].code = setjmp(ctx->error->stack[ctx->error->top].buffer)) == 0) \ - { do { - -#define fz_always(ctx) \ - } while (0); \ - longjmp(ctx->error->stack[ctx->error->top].buffer, 3); \ - } \ - else if (ctx->error->stack[ctx->error->top].code & 1) \ - { do { - -#define fz_catch(ctx) \ - } while(0); \ - if (ctx->error->stack[ctx->error->top].code == 1) \ - longjmp(ctx->error->stack[ctx->error->top].buffer, 2); \ - ctx->error->top--;\ - } \ - else if (ctx->error->top--, 1) - -*/ - void fz_push_try(fz_error_context *ex); void fz_throw(fz_context *, char *, ...) __printflike(2, 3); void fz_rethrow(fz_context *); +void fz_warn(fz_context *ctx, char *fmt, ...) __printflike(2, 3); -struct fz_warn_context_s -{ - char message[256]; - int count; -}; +/* + fz_flush_warnings: Flush any repeated warnings. -void fz_warn(fz_context *ctx, char *fmt, ...) __printflike(2, 3); + Repeated warnings are buffered, counted and eventually printed + along with the number of repetitions. Call fz_flush_warnings + to force printing of the latest buffered warning and the + number of repetitions, for example to make sure that all + warnings are printed before exiting an application. + + Does not throw exceptions. +*/ void fz_flush_warnings(fz_context *ctx); struct fz_context_s @@ -371,42 +203,118 @@ struct fz_context_s fz_glyph_cache *glyph_cache; }; +/* + Specifies the maximum size in bytes of the resource store in + fz_context. Given as argument to fz_new_context. + + FZ_STORE_UNLIMITED: Let resource store grow unbounded. + + FZ_STORE_DEFAULT: A reasonable upper bound on the size, for + devices that are not memory constrained. +*/ +enum { + FZ_STORE_UNLIMITED = 0, + FZ_STORE_DEFAULT = 256 << 20, +}; + +/* + fz_new_context: Allocate context containing global state. + + The global state contains an exception stack, resource store, + etc. Most functions in MuPDF take a context argument to be + able to reference the global state. See fz_free_context for + freeing an allocated context. + + alloc: Supply a custom memory allocator through a set of + function pointers. Set to NULL for the standard library + allocator. The context will keep the allocator pointer, so the + data it points to must not be modified or freed during the + lifetime of the context. + + locks: Supply a set of locks and functions to lock/unlock + them, intended for multi-threaded applications. Set to NULL + when using MuPDF in a single-threaded applications. The + context will keep the locks pointer, so the data it points to + must not be modified or freed during the lifetime of the + context. + + max_store: Maximum size in bytes of the resource store, before + it will start evicting cached resources such as fonts and + images. FZ_STORE_UNLIMITED can be used if a hard limit is not + desired. Use FZ_STORE_DEFAULT to get a reasonable size. + + Does not throw exceptions, but may return NULL. +*/ fz_context *fz_new_context(fz_alloc_context *alloc, fz_locks_context *locks, unsigned int max_store); + +/* + fz_clone_context: Make a clone of an existing context. + + This function is meant to be used in multi-threaded + applications where each thread requires its own context, yet + parts of the global state, for example caching, is shared. + + ctx: Context obtained from fz_new_context to make a copy of. + ctx must have had locks and lock/functions setup when created. + The two contexts will share the memory allocator, resource + store, locks and lock/unlock functions. They will each have + their own exception stacks though. + + Does not throw exception, but may return NULL. +*/ fz_context *fz_clone_context(fz_context *ctx); -fz_context *fz_clone_context_internal(fz_context *ctx); + +/* + fz_free_context: Free a context and its global state. + + The context and all of its global state is freed, and any + buffered warnings are flushed (see fz_flush_warnings). If NULL + is passed in nothing will happen. + + Does not throw exceptions. +*/ void fz_free_context(fz_context *ctx); -void fz_new_aa_context(fz_context *ctx); -void fz_free_aa_context(fz_context *ctx); - -/* Locking functions - * - * MuPDF is kept deliberately free of any knowledge of particular threading - * systems. As such, in order for safe multi-threaded operation, we rely on - * callbacks to client provided functions. - * - * A client is expected to provide FZ_LOCK_MAX mutexes, and a function to - * lock/unlock each of them. These may be recursive mutexes, but do not have - * to be. - * - * If a client does not intend to use multiple threads, then it may pass - * NULL instead of the address of a lock structure. - * - * In order to avoid deadlocks, we have 1 simple rules internally as to how - * we use locks: We can never take lock n when we already hold any lock i, - * where 0 <= i <= n. In order to verify this, we have some debugging code - * built in, that is enabled by defining FITZ_DEBUG_LOCKING. - */ +/* + fz_aa_level: Get the number of bits of antialiasing we are + using. Between 0 and 8. +*/ +int fz_aa_level(fz_context *ctx); -#if defined(MEMENTO) || defined(DEBUG) -#define FITZ_DEBUG_LOCKING -#endif +/* + fz_set_aa_level: Set the number of bits of antialiasing we should use. + + bits: The number of bits of antialiasing to use (values are clamped + to within the 0 to 8 range). +*/ +void fz_set_aa_level(fz_context *ctx, int bits); + +/* + Locking functions + + MuPDF is kept deliberately free of any knowledge of particular + threading systems. As such, in order for safe multi-threaded + operation, we rely on callbacks to client provided functions. + + A client is expected to provide FZ_LOCK_MAX number of mutexes, + and a function to lock/unlock each of them. These may be + recursive mutexes, but do not have to be. + + If a client does not intend to use multiple threads, then it + may pass NULL instead of a lock structure. + + In order to avoid deadlocks, we have one simple rule + internally as to how we use locks: We can never take lock n + when we already hold any lock i, where 0 <= i <= n. In order + to verify this, we have some debugging code, that can be + enabled by defining FITZ_DEBUG_LOCKING. +*/ struct fz_locks_context_s { void *user; - void (*lock)(void *, int); - void (*unlock)(void *, int); + void (*lock)(void *user, int lock); + void (*unlock)(void *user, int lock); }; enum { @@ -417,1076 +325,1257 @@ enum { FZ_LOCK_MAX }; -/* Default locks */ -extern fz_locks_context fz_locks_default; +/* + Memory Allocation and Scavenging: -#ifdef FITZ_DEBUG_LOCKING + All calls to MuPDFs allocator functions pass through to the + underlying allocators passed in when the initial context is + created, after locks are taken (using the supplied locking function) + to ensure that only one thread at a time calls through. -void fz_assert_lock_held(fz_context *ctx, int lock); -void fz_assert_lock_not_held(fz_context *ctx, int lock); -void fz_lock_debug_lock(fz_context *ctx, int lock); -void fz_lock_debug_unlock(fz_context *ctx, int lock); + If the underlying allocator fails, MuPDF attempts to make room for + the allocation by evicting elements from the store, then retrying. -#else + Any call to allocate may then result in several calls to the underlying + allocator, and result in elements that are only referred to by the + store being freed. +*/ -#define fz_assert_lock_held(A,B) do { } while (0) -#define fz_assert_lock_not_held(A,B) do { } while (0) -#define fz_lock_debug_lock(A,B) do { } while (0) -#define fz_lock_debug_unlock(A,B) do { } while (0) +/* + fz_malloc: Allocate a block of memory (with scavenging) -#endif /* !FITZ_DEBUG_LOCKING */ + size: The number of bytes to allocate. -static inline void -fz_lock(fz_context *ctx, int lock) -{ - fz_lock_debug_lock(ctx, lock); - ctx->locks->lock(ctx->locks->user, lock); -} + Returns a pointer to the allocated block. May return NULL if size is + 0. Throws exception on failure to allocate. +*/ +void *fz_malloc(fz_context *ctx, unsigned int size); -static inline void -fz_unlock(fz_context *ctx, int lock) -{ - fz_lock_debug_unlock(ctx, lock); - ctx->locks->unlock(ctx->locks->user, lock); -} +/* + fz_calloc: Allocate a zeroed block of memory (with scavenging) + + count: The number of objects to allocate space for. + size: The size (in bytes) of each object. + + Returns a pointer to the allocated block. May return NULL if size + and/or count are 0. Throws exception on failure to allocate. +*/ +void *fz_calloc(fz_context *ctx, unsigned int count, unsigned int size); /* - * Basic runtime and utility functions - */ + fz_malloc_array: Allocate a block of (non zeroed) memory (with + scavenging). Equivalent to fz_calloc without the memory clearing. -/* memory allocation */ + count: The number of objects to allocate space for. -/* The following throw exceptions on failure to allocate */ -void *fz_malloc(fz_context *ctx, unsigned int size); -void *fz_calloc(fz_context *ctx, unsigned int count, unsigned int size); + size: The size (in bytes) of each object. + + Returns a pointer to the allocated block. May return NULL if size + and/or count are 0. Throws exception on failure to allocate. +*/ void *fz_malloc_array(fz_context *ctx, unsigned int count, unsigned int size); + +/* + fz_resize_array: Resize a block of memory (with scavenging). + + p: The existing block to resize + + count: The number of objects to resize to. + + size: The size (in bytes) of each object. + + Returns a pointer to the resized block. May return NULL if size + and/or count are 0. Throws exception on failure to resize (original + block is left unchanged). +*/ void *fz_resize_array(fz_context *ctx, void *p, unsigned int count, unsigned int size); + +/* + fz_strdup: Duplicate a C string (with scavenging) + + s: The string to duplicate. + + Returns a pointer to a duplicated string. Throws exception on failure + to allocate. +*/ char *fz_strdup(fz_context *ctx, char *s); +/* + fz_free: Frees an allocation. + + Does not throw exceptions. +*/ void fz_free(fz_context *ctx, void *p); -/* The following returns NULL on failure to allocate */ +/* + fz_malloc_no_throw: Allocate a block of memory (with scavenging) + + size: The number of bytes to allocate. + + Returns a pointer to the allocated block. May return NULL if size is + 0. Returns NULL on failure to allocate. +*/ void *fz_malloc_no_throw(fz_context *ctx, unsigned int size); -void *fz_malloc_array_no_throw(fz_context *ctx, unsigned int count, unsigned int size); + +/* + fz_calloc_no_throw: Allocate a zeroed block of memory (with scavenging) + + count: The number of objects to allocate space for. + + size: The size (in bytes) of each object. + + Returns a pointer to the allocated block. May return NULL if size + and/or count are 0. Returns NULL on failure to allocate. +*/ void *fz_calloc_no_throw(fz_context *ctx, unsigned int count, unsigned int size); + +/* + fz_malloc_array_no_throw: Allocate a block of (non zeroed) memory + (with scavenging). Equivalent to fz_calloc_no_throw without the + memory clearing. + + count: The number of objects to allocate space for. + + size: The size (in bytes) of each object. + + Returns a pointer to the allocated block. May return NULL if size + and/or count are 0. Returns NULL on failure to allocate. +*/ +void *fz_malloc_array_no_throw(fz_context *ctx, unsigned int count, unsigned int size); + +/* + fz_resize_array_no_throw: Resize a block of memory (with scavenging). + + p: The existing block to resize + + count: The number of objects to resize to. + + size: The size (in bytes) of each object. + + Returns a pointer to the resized block. May return NULL if size + and/or count are 0. Returns NULL on failure to resize (original + block is left unchanged). +*/ void *fz_resize_array_no_throw(fz_context *ctx, void *p, unsigned int count, unsigned int size); + +/* + fz_strdup_no_throw: Duplicate a C string (with scavenging) + + s: The string to duplicate. + + Returns a pointer to a duplicated string. Returns NULL on failure + to allocate. +*/ char *fz_strdup_no_throw(fz_context *ctx, char *s); -/* alloc and zero a struct, and tag it for memento */ -#define fz_malloc_struct(CTX, STRUCT) \ - Memento_label(fz_calloc(CTX,1,sizeof(STRUCT)), #STRUCT) +/* + Safe string functions +*/ +/* + fz_strsep: Given a pointer to a C string (or a pointer to NULL) break + it at the first occurence of a delimiter char (from a given set). -/* runtime (hah!) test for endian-ness */ -int fz_is_big_endian(void); + stringp: Pointer to a C string pointer (or NULL). Updated on exit to + point to the first char of the string after the delimiter that was + found. The string pointed to by stringp will be corrupted by this + call (as the found delimiter will be overwritten by 0). -/* safe string functions */ + delim: A C string of acceptable delimiter characters. + + Returns a pointer to a C string containing the chars of stringp up + to the first delimiter char (or the end of the string), or NULL. +*/ char *fz_strsep(char **stringp, const char *delim); -int fz_strlcpy(char *dst, const char *src, int n); -int fz_strlcat(char *dst, const char *src, int n); -/* Range checking atof */ -float fz_atof(const char *s); +/* + fz_strlcpy: Copy at most n-1 chars of a string into a destination + buffer with null termination, returning the real length of the + initial string (excluding terminator). -/* utf-8 encoding and decoding */ -int chartorune(int *rune, char *str); -int runetochar(char *str, int *rune); -int runelen(int c); + dst: Destination buffer, at least n bytes long. -/* getopt */ -extern int fz_getopt(int nargc, char * const *nargv, const char *ostr); -extern int fz_optind; -extern char *fz_optarg; + src: C string (non-NULL). + + n: Size of dst buffer in bytes. + + Returns the length (excluding terminator) of src. +*/ +int fz_strlcpy(char *dst, const char *src, int n); /* - * Generic hash-table with fixed-length keys. - */ + fz_strlcat: Concatenate 2 strings, with a maximum length. -typedef struct fz_hash_table_s fz_hash_table; + dst: pointer to first string in a buffer of n bytes. -fz_hash_table *fz_new_hash_table(fz_context *ctx, int initialsize, int keylen); -void fz_debug_hash(fz_context *ctx, fz_hash_table *table); -void fz_empty_hash(fz_context *ctx, fz_hash_table *table); -void fz_free_hash(fz_context *ctx, fz_hash_table *table); + src: pointer to string to concatenate. -void *fz_hash_find(fz_context *ctx, fz_hash_table *table, void *key); -void *fz_hash_insert(fz_context *ctx, fz_hash_table *table, void *key, void *val); -void fz_hash_remove(fz_context *ctx, fz_hash_table *table, void *key); + n: Size (in bytes) of buffer that dst is in. -int fz_hash_len(fz_context *ctx, fz_hash_table *table); -void *fz_hash_get_key(fz_context *ctx, fz_hash_table *table, int idx); -void *fz_hash_get_val(fz_context *ctx, fz_hash_table *table, int idx); + Returns the real length that a concatenated dst + src would have been + (not including terminator). +*/ +int fz_strlcat(char *dst, const char *src, int n); /* - * Math and geometry - */ + fz_chartorune: UTF8 decode a string of chars to a rune. -/* Multiply scaled two integers in the 0..255 range */ -static inline int fz_mul255(int a, int b) -{ - /* see Jim Blinn's book "Dirty Pixels" for how this works */ - int x = a * b + 128; - x += x >> 8; - return x >> 8; -} + rune: Pointer to an int to assign the decoded 'rune' to. -/* Expand a value A from the 0...255 range to the 0..256 range */ -#define FZ_EXPAND(A) ((A)+((A)>>7)) + str: Pointer to a UTF8 encoded string -/* Combine values A (in any range) and B (in the 0..256 range), - * to give a single value in the same range as A was. */ -#define FZ_COMBINE(A,B) (((A)*(B))>>8) + Returns the number of bytes consumed. Does not throw exceptions. +*/ +int fz_chartorune(int *rune, char *str); -/* Combine values A and C (in the same (any) range) and B and D (in the - * 0..256 range), to give a single value in the same range as A and C were. */ -#define FZ_COMBINE2(A,B,C,D) (FZ_COMBINE((A), (B)) + FZ_COMBINE((C), (D))) +/* + runetochar: UTF8 encode a run to a string of chars. -/* Blend SRC and DST (in the same range) together according to - * AMOUNT (in the 0...256 range). */ -#define FZ_BLEND(SRC, DST, AMOUNT) ((((SRC)-(DST))*(AMOUNT) + ((DST)<<8))>>8) + str: Pointer to a place to put the UTF8 encoded string. -typedef struct fz_matrix_s fz_matrix; -typedef struct fz_point_s fz_point; -typedef struct fz_rect_s fz_rect; -typedef struct fz_bbox_s fz_bbox; + rune: Pointer to a 'rune'. -extern const fz_rect fz_unit_rect; -extern const fz_rect fz_empty_rect; -extern const fz_rect fz_infinite_rect; + Returns the number of bytes the rune took to output. Does not throw + exceptions. +*/ +int fz_runetochar(char *str, int rune); -extern const fz_bbox fz_unit_bbox; -extern const fz_bbox fz_empty_bbox; -extern const fz_bbox fz_infinite_bbox; +/* + fz_runelen: Count many chars are required to represent a rune. -#define fz_is_empty_rect(r) ((r).x0 == (r).x1) -#define fz_is_infinite_rect(r) ((r).x0 > (r).x1) -#define fz_is_empty_bbox(b) ((b).x0 == (b).x1) -#define fz_is_infinite_bbox(b) ((b).x0 > (b).x1) + rune: The rune to encode. -struct fz_matrix_s -{ - float a, b, c, d, e, f; -}; + Returns the number of bytes required to represent this run in UTF8. +*/ +int fz_runelen(int rune); +/* getopt */ +extern int fz_getopt(int nargc, char * const *nargv, const char *ostr); +extern int fz_optind; +extern char *fz_optarg; + +/* + fz_point is a point in a two-dimensional space. +*/ +typedef struct fz_point_s fz_point; struct fz_point_s { float x, y; }; +/* + fz_rect is a rectangle represented by two diagonally opposite + corners at arbitrary coordinates. + + Rectangles are always axis-aligned with the X- and Y- axes. + The relationship between the coordinates are that x0 <= x1 and + y0 <= y1 in all cases except for infinte rectangles. The area + of a rectangle is defined as (x1 - x0) * (y1 - y0). If either + x0 > x1 or y0 > y1 is true for a given rectangle then it is + defined to be infinite. + + To check for empty or infinite rectangles use fz_is_empty_rect + and fz_is_infinite_rect. Compare to fz_bbox which has corners + at integer coordinates. + + x0, y0: The top left corner. + + x1, y1: The botton right corner. +*/ +typedef struct fz_rect_s fz_rect; struct fz_rect_s { float x0, y0; float x1, y1; }; +/* + fz_bbox is a bounding box similar to a fz_rect, except that + all corner coordinates are rounded to integer coordinates. + To check for empty or infinite bounding boxes use + fz_is_empty_bbox and fz_is_infinite_bbox. + + x0, y0: The top left corner. + + x1, y1: The bottom right corner. +*/ +typedef struct fz_bbox_s fz_bbox; struct fz_bbox_s { int x0, y0; int x1, y1; }; +/* + A rectangle with sides of length one. + + The bottom left corner is at (0, 0) and the top right corner + is at (1, 1). +*/ +extern const fz_rect fz_unit_rect; + +/* + A bounding box with sides of length one. See fz_unit_rect. +*/ +extern const fz_bbox fz_unit_bbox; + +/* + An empty rectangle with an area equal to zero. + + Both the top left and bottom right corner are at (0, 0). +*/ +extern const fz_rect fz_empty_rect; + +/* + An empty bounding box. See fz_empty_rect. +*/ +extern const fz_bbox fz_empty_bbox; + +/* + An infinite rectangle with negative area. + + The corner (x0, y0) is at (1, 1) while the corner (x1, y1) is + at (-1, -1). +*/ +extern const fz_rect fz_infinite_rect; + +/* + An infinite bounding box. See fz_infinite_rect. +*/ +extern const fz_bbox fz_infinite_bbox; + +/* + fz_is_empty_rect: Check if rectangle is empty. + + An empty rectangle is defined as one whose area is zero. +*/ +#define fz_is_empty_rect(r) ((r).x0 == (r).x1 || (r).y0 == (r).y1) + +/* + fz_is_empty_bbox: Check if bounding box is empty. + + Same definition of empty bounding boxes as for empty + rectangles. See fz_is_empty_rect. +*/ +#define fz_is_empty_bbox(b) ((b).x0 == (b).x1 || (b).y0 == (b).y1) + +/* + fz_is_infinite: Check if rectangle is infinite. + + An infinite rectangle is defined as one where either of the + two relationships between corner coordinates are not true. +*/ +#define fz_is_infinite_rect(r) ((r).x0 > (r).x1 || (r).y0 > (r).y1) + +/* + fz_is_infinite_bbox: Check if bounding box is infinite. + + Same definition of infinite bounding boxes as for infinite + rectangles. See fz_is_infinite_rect. +*/ +#define fz_is_infinite_bbox(b) ((b).x0 > (b).x1 || (b).y0 > (b).y1) + +/* + fz_matrix is a a row-major 3x3 matrix used for representing + transformations of coordinates throughout MuPDF. + + Since all points reside in a two-dimensional space, one vector + is always a constant unit vector; hence only some elements may + vary in a matrix. Below is how the elements map between + different representations. + + / a b 0 \ + | c d 0 | normally represented as [ a b c d e f ]. + \ e f 1 / +*/ +typedef struct fz_matrix_s fz_matrix; +struct fz_matrix_s +{ + float a, b, c, d, e, f; +}; + + +/* + fz_identity: Identity transform matrix. +*/ extern const fz_matrix fz_identity; -fz_matrix fz_concat(fz_matrix one, fz_matrix two); +/* + fz_concat: Multiply two matrices. + + The order of the two matrices are important since matrix + multiplication is not commutative. + + Does not throw exceptions. +*/ +fz_matrix fz_concat(fz_matrix left, fz_matrix right); + +/* + fz_scale: Create a scaling matrix. + + The returned matrix is of the form [ sx 0 0 sy 0 0 ]. + + sx, sy: Scaling factors along the X- and Y-axes. A scaling + factor of 1.0 will not cause any scaling along the relevant + axis. + + Does not throw exceptions. +*/ fz_matrix fz_scale(float sx, float sy); + +/* + fz_shear: Create a shearing matrix. + + The returned matrix is of the form [ 1 sy sx 1 0 0 ]. + + sx, sy: Shearing factors. A shearing factor of 0.0 will not + cause any shearing along the relevant axis. + + Does not throw exceptions. +*/ fz_matrix fz_shear(float sx, float sy); -fz_matrix fz_rotate(float theta); + +/* + fz_rotate: Create a rotation matrix. + + The returned matrix is of the form + [ cos(deg) sin(deg) -sin(deg) cos(deg) 0 0 ]. + + degrees: Degrees of counter clockwise rotation. Values less + than zero and greater than 360 are handled as expected. + + Does not throw exceptions. +*/ +fz_matrix fz_rotate(float degrees); + +/* + fz_translate: Create a translation matrix. + + The returned matrix is of the form [ 1 0 0 1 tx ty ]. + + tx, ty: Translation distances along the X- and Y-axes. A + translation of 0 will not cause any translation along the + relevant axis. + + Does not throw exceptions. +*/ fz_matrix fz_translate(float tx, float ty); -fz_matrix fz_invert_matrix(fz_matrix m); + +/* + fz_invert_matrix: Create an inverse matrix. + + matrix: Matrix to invert. A degenerate matrix, where the + determinant is equal to zero, can not be inverted and the + original matrix is returned instead. + + Does not throw exceptions. +*/ +fz_matrix fz_invert_matrix(fz_matrix matrix); + +/* + fz_is_rectilinear: Check if a transformation is rectilinear. + + Rectilinear means that no shearing is present and that any + rotations present are a multiple of 90 degrees. Usually this + is used to make sure that axis-aligned rectangles before the + transformation are still axis-aligned rectangles afterwards. + + Does not throw exceptions. +*/ int fz_is_rectilinear(fz_matrix m); -float fz_matrix_expansion(fz_matrix m); -float fz_matrix_max_expansion(fz_matrix m); -fz_bbox fz_round_rect(fz_rect r); -fz_bbox fz_intersect_bbox(fz_bbox a, fz_bbox b); -fz_rect fz_intersect_rect(fz_rect a, fz_rect b); -fz_bbox fz_union_bbox(fz_bbox a, fz_bbox b); -fz_rect fz_union_rect(fz_rect a, fz_rect b); +/* + fz_matrix_expansion: Calculate average scaling factor of matrix. +*/ +float fz_matrix_expansion(fz_matrix m); /* sumatrapdf */ + +/* + fz_round_rect: Convert a rect into a bounding box. -fz_point fz_transform_point(fz_matrix m, fz_point p); -fz_point fz_transform_vector(fz_matrix m, fz_point p); -fz_rect fz_transform_rect(fz_matrix m, fz_rect r); -fz_bbox fz_transform_bbox(fz_matrix m, fz_bbox b); + Coordinates in a bounding box are integers, so rounding of the + rects coordinates takes place. The top left corner is rounded + upwards and left while the bottom right corner is rounded + downwards and to the right. Overflows or underflowing + coordinates are clamped to INT_MIN/INT_MAX. -void fz_gridfit_matrix(fz_matrix *m); + Does not throw exceptions. +*/ +fz_bbox fz_round_rect(fz_rect rect); /* - * Basic crypto functions. - * Independent of the rest of fitz. - * For further encapsulation in filters, or not. - */ + fz_intersect_rect: Compute intersection of two rectangles. -/* md5 digests */ + Compute the largest axis-aligned rectangle that covers the + area covered by both given rectangles. If either rectangle is + empty then the intersection is also empty. If either rectangle + is infinite then the intersection is simply the non-infinite + rectangle. Should both rectangles be infinite, then the + intersection is also infinite. -typedef struct fz_md5_s fz_md5; + Does not throw exceptions. +*/ +fz_rect fz_intersect_rect(fz_rect a, fz_rect b); -struct fz_md5_s -{ - unsigned int state[4]; - unsigned int count[2]; - unsigned char buffer[64]; -}; +/* + fz_intersect_bbox: Compute intersection of two bounding boxes. -void fz_md5_init(fz_md5 *state); -void fz_md5_update(fz_md5 *state, const unsigned char *input, unsigned inlen); -void fz_md5_final(fz_md5 *state, unsigned char digest[16]); + Similar to fz_intersect_rect but operates on two bounding + boxes instead of two rectangles. -/* sha-256 digests */ + Does not throw exceptions. +*/ +fz_bbox fz_intersect_bbox(fz_bbox a, fz_bbox b); -typedef struct fz_sha256_s fz_sha256; +/* + fz_union_rect: Compute union of two rectangles. -struct fz_sha256_s -{ - unsigned int state[8]; - unsigned int count[2]; - union { - unsigned char u8[64]; - unsigned int u32[16]; - } buffer; -}; + Compute the smallest axis-aligned rectangle that encompasses + both given rectangles. If either rectangle is infinite then + the union is also infinite. If either rectangle is empty then + the union is simply the non-empty rectangle. Should both + rectangles be empty, then the union is also empty. -void fz_sha256_init(fz_sha256 *state); -void fz_sha256_update(fz_sha256 *state, const unsigned char *input, unsigned int inlen); -void fz_sha256_final(fz_sha256 *state, unsigned char digest[32]); + Does not throw exceptions. +*/ +fz_rect fz_union_rect(fz_rect a, fz_rect b); -/* arc4 crypto */ +/* + fz_union_bbox: Compute union of two bounding boxes. -typedef struct fz_arc4_s fz_arc4; + Similar to fz_union_rect but operates on two bounding boxes + instead of two rectangles. -struct fz_arc4_s -{ - unsigned x; - unsigned y; - unsigned char state[256]; -}; + Does not throw exceptions. +*/ +fz_bbox fz_union_bbox(fz_bbox a, fz_bbox b); -void fz_arc4_init(fz_arc4 *state, const unsigned char *key, unsigned len); -void fz_arc4_encrypt(fz_arc4 *state, unsigned char *dest, const unsigned char *src, unsigned len); +/* + fz_transform_point: Apply a transformation to a point. -/* AES block cipher implementation from XYSSL */ + transform: Transformation matrix to apply. See fz_concat, + fz_scale, fz_rotate and fz_translate for how to create a + matrix. -typedef struct fz_aes_s fz_aes; + Does not throw exceptions. +*/ +fz_point fz_transform_point(fz_matrix transform, fz_point point); -#define AES_DECRYPT 0 -#define AES_ENCRYPT 1 +/* + fz_transform_vector: Apply a transformation to a vector. -struct fz_aes_s -{ - int nr; /* number of rounds */ - unsigned long *rk; /* AES round keys */ - unsigned long buf[68]; /* unaligned data */ -}; + transform: Transformation matrix to apply. See fz_concat, + fz_scale and fz_rotate for how to create a matrix. Any + translation will be ignored. -void aes_setkey_enc( fz_aes *ctx, const unsigned char *key, int keysize ); -void aes_setkey_dec( fz_aes *ctx, const unsigned char *key, int keysize ); -void aes_crypt_cbc( fz_aes *ctx, int mode, int length, - unsigned char iv[16], - const unsigned char *input, - unsigned char *output ); + Does not throw exceptions. +*/ +fz_point fz_transform_vector(fz_matrix transform, fz_point vector); /* - * Dynamic objects. - * The same type of objects as found in PDF and PostScript. - * Used by the filters and the mupdf parser. - */ + fz_transform_rect: Apply a transform to a rectangle. -typedef struct fz_obj_s fz_obj; - -extern fz_obj *(*fz_resolve_indirect)(fz_obj *obj); - -fz_obj *fz_new_null(fz_context *ctx); -fz_obj *fz_new_bool(fz_context *ctx, int b); -fz_obj *fz_new_int(fz_context *ctx, int i); -fz_obj *fz_new_real(fz_context *ctx, float f); -fz_obj *fz_new_name(fz_context *ctx, char *str); -fz_obj *fz_new_string(fz_context *ctx, char *str, int len); -fz_obj *fz_new_indirect(fz_context *ctx, int num, int gen, void *doc); - -fz_obj *fz_new_array(fz_context *ctx, int initialcap); -fz_obj *fz_new_dict(fz_context *ctx, int initialcap); -fz_obj *fz_copy_array(fz_context *ctx, fz_obj *array); -fz_obj *fz_copy_dict(fz_context *ctx, fz_obj *dict); - -fz_obj *fz_keep_obj(fz_obj *obj); -void fz_drop_obj(fz_obj *obj); - -/* type queries */ -int fz_is_null(fz_obj *obj); -int fz_is_bool(fz_obj *obj); -int fz_is_int(fz_obj *obj); -int fz_is_real(fz_obj *obj); -int fz_is_name(fz_obj *obj); -int fz_is_string(fz_obj *obj); -int fz_is_array(fz_obj *obj); -int fz_is_dict(fz_obj *obj); -int fz_is_indirect(fz_obj *obj); - -int fz_objcmp(fz_obj *a, fz_obj *b); - -/* dict marking and unmarking functions - to avoid infinite recursions */ -int fz_dict_marked(fz_obj *obj); -int fz_dict_mark(fz_obj *obj); -void fz_dict_unmark(fz_obj *obj); - -/* safe, silent failure, no error reporting on type mismatches */ -int fz_to_bool(fz_obj *obj); -int fz_to_int(fz_obj *obj); -float fz_to_real(fz_obj *obj); -char *fz_to_name(fz_obj *obj); -char *fz_to_str_buf(fz_obj *obj); -fz_obj *fz_to_dict(fz_obj *obj); -int fz_to_str_len(fz_obj *obj); -int fz_to_num(fz_obj *obj); -int fz_to_gen(fz_obj *obj); - -int fz_array_len(fz_obj *array); -fz_obj *fz_array_get(fz_obj *array, int i); -void fz_array_put(fz_obj *array, int i, fz_obj *obj); -void fz_array_push(fz_obj *array, fz_obj *obj); -void fz_array_insert(fz_obj *array, fz_obj *obj); -int fz_array_contains(fz_obj *array, fz_obj *obj); - -int fz_dict_len(fz_obj *dict); -fz_obj *fz_dict_get_key(fz_obj *dict, int idx); -fz_obj *fz_dict_get_val(fz_obj *dict, int idx); -fz_obj *fz_dict_get(fz_obj *dict, fz_obj *key); -fz_obj *fz_dict_gets(fz_obj *dict, char *key); -fz_obj *fz_dict_getsa(fz_obj *dict, char *key, char *abbrev); -void fz_dict_put(fz_obj *dict, fz_obj *key, fz_obj *val); -void fz_dict_puts(fz_obj *dict, char *key, fz_obj *val); -void fz_dict_del(fz_obj *dict, fz_obj *key); -void fz_dict_dels(fz_obj *dict, char *key); -void fz_sort_dict(fz_obj *dict); - -int fz_fprint_obj(FILE *fp, fz_obj *obj, int tight); -void fz_debug_obj(fz_obj *obj); -void fz_debug_ref(fz_obj *obj); - -void fz_set_str_len(fz_obj *obj, int newlen); /* private */ -void *fz_get_indirect_document(fz_obj *obj); /* private */ - -/* - * Data buffers. - */ + After the four corner points of the axis-aligned rectangle + have been transformed it may not longer be axis-aligned. So a + new axis-aligned rectangle is created covering at least the + area of the transformed rectangle. + transform: Transformation matrix to apply. See fz_concat, + fz_scale and fz_rotate for how to create a matrix. + + rect: Rectangle to be transformed. The two special cases + fz_empty_rect and fz_infinite_rect, may be used but are + returned unchanged as expected. + + Does not throw exceptions. +*/ +fz_rect fz_transform_rect(fz_matrix transform, fz_rect rect); + +/* + fz_transform_bbox: Transform a given bounding box. + + Similar to fz_transform_rect, but operates on a bounding box + instead of a rectangle. + + Does not throw exceptions. +*/ +fz_bbox fz_transform_bbox(fz_matrix matrix, fz_bbox bbox); + +/* + fz_buffer is a wrapper around a dynamically allocated array of bytes. + + Buffers have a capacity (the number of bytes storage immediately + available) and a current size. +*/ typedef struct fz_buffer_s fz_buffer; -struct fz_buffer_s -{ - int refs; - unsigned char *data; - int cap, len; -}; +/* + fz_keep_buffer: Increment the reference count for a buffer. -fz_buffer *fz_new_buffer(fz_context *ctx, int size); + buf: The buffer to increment the reference count for. + + Returns a pointer to the buffer. Does not throw exceptions. +*/ fz_buffer *fz_keep_buffer(fz_context *ctx, fz_buffer *buf); + +/* + fz_drop_buffer: Decrement the reference count for a buffer. + + buf: The buffer to decrement the reference count for. +*/ void fz_drop_buffer(fz_context *ctx, fz_buffer *buf); -void fz_resize_buffer(fz_context *ctx, fz_buffer *buf, int size); -void fz_grow_buffer(fz_context *ctx, fz_buffer *buf); +/* + fz_buffer_storage: Retrieve information on the storage currently used + by a buffer. + + data: Pointer to place to retrieve data pointer. + + Returns length of stream. +*/ +int fz_buffer_storage(fz_context *ctx, fz_buffer *buf, unsigned char **data); /* - * Resource store - */ + fz_stream is a buffered reader capable of seeking in both + directions. -typedef struct fz_storable_s fz_storable; + Streams are reference counted, so references must be dropped + by a call to fz_close. -typedef struct fz_item_s fz_item; + Only the data between rp and wp is valid. +*/ +typedef struct fz_stream_s fz_stream; -typedef void (fz_store_free_fn)(fz_context *, fz_storable *); +/* + fz_open_file: Open the named file and wrap it in a stream. -struct fz_storable_s { - int refs; - fz_store_free_fn *free; -}; + filename: Path to a file as it would be given to open(2). +*/ +fz_stream *fz_open_file(fz_context *ctx, const char *filename); -#define FZ_INIT_STORABLE(S_,RC,FREE) \ - do { fz_storable *S = &(S_)->storable; S->refs = (RC); \ - S->free = (FREE); \ - } while (0) +/* + fz_open_file_w: Open the named file and wrap it in a stream. -enum { - FZ_STORE_UNLIMITED = 0, - FZ_STORE_DEFAULT = 256 << 20, -}; + This function is only available when compiling for Win32. -void fz_new_store_context(fz_context *ctx, unsigned int max); -void fz_drop_store_context(fz_context *ctx); -fz_store *fz_store_keep(fz_context *ctx); -void fz_debug_store(fz_context *ctx); + filename: Wide character path to the file as it would be given + to _wopen(). +*/ +fz_stream *fz_open_file_w(fz_context *ctx, const wchar_t *filename); -void *fz_keep_storable(fz_context *, fz_storable *); -void fz_drop_storable(fz_context *, fz_storable *); +/* + fz_open_fd: Wrap an open file descriptor in a stream. -void fz_store_item(fz_context *ctx, fz_obj *key, void *val, unsigned int itemsize); -void *fz_find_item(fz_context *ctx, fz_store_free_fn *freefn, fz_obj *key); -void fz_remove_item(fz_context *ctx, fz_store_free_fn *freefn, fz_obj *key); -void fz_empty_store(fz_context *ctx); -int fz_store_scavenge(fz_context *ctx, unsigned int size, int *phase); + file: An open file descriptor supporting bidirectional + seeking. The stream will take ownership of the file + descriptor, so it may not be modified or closed after the call + to fz_open_fd. When the stream is closed it will also close + the file descriptor. +*/ +fz_stream *fz_open_fd(fz_context *ctx, int file); /* - * Buffered reader. - * Only the data between rp and wp is valid data. - */ + fz_open_memory: Open a block of memory as a stream. -typedef struct fz_stream_s fz_stream; + data: Pointer to start of data block. Ownership of the data block is + NOT passed in. -struct fz_stream_s -{ - fz_context *ctx; - int refs; - int error; - int eof; - int pos; - int avail; - int bits; - int locked; - unsigned char *bp, *rp, *wp, *ep; - void *state; - int (*read)(fz_stream *stm, unsigned char *buf, int len); - void (*close)(fz_context *ctx, void *state); - void (*seek)(fz_stream *stm, int offset, int whence); - unsigned char buf[4096]; -}; + len: Number of bytes in data block. -fz_stream *fz_open_fd(fz_context *ctx, int file); -fz_stream *fz_open_file(fz_context *ctx, const char *filename); -fz_stream *fz_open_file_w(fz_context *ctx, const wchar_t *filename); /* only on win32 */ -fz_stream *fz_open_buffer(fz_context *ctx, fz_buffer *buf); + Returns pointer to newly created stream. May throw exceptions on + failure to allocate. +*/ fz_stream *fz_open_memory(fz_context *ctx, unsigned char *data, int len); -void fz_close(fz_stream *stm); -void fz_lock_stream(fz_stream *stm); -fz_stream *fz_new_stream(fz_context *ctx, void*, int(*)(fz_stream*, unsigned char*, int), void(*)(fz_context *, void *)); -fz_stream *fz_keep_stream(fz_stream *stm); -void fz_fill_buffer(fz_stream *stm); +/* + fz_open_buffer: Open a buffer as a stream. + + buf: The buffer to open. Ownership of the buffer is NOT passed in + (this function takes it's own reference). + Returns pointer to newly created stream. May throw exceptions on + failure to allocate. +*/ +fz_stream *fz_open_buffer(fz_context *ctx, fz_buffer *buf); + +/* + fz_close: Close an open stream. + + Drops a reference for the stream. Once no references remain + the stream will be closed, as will any file descriptor the + stream is using. + + Does not throw exceptions. +*/ +void fz_close(fz_stream *stm); + +/* + fz_tell: return the current reading position within a stream +*/ int fz_tell(fz_stream *stm); + +/* + fz_seek: Seek within a stream. + + stm: The stream to seek within. + + offset: The offset to seek to. + + whence: From where the offset is measured (see fseek). +*/ void fz_seek(fz_stream *stm, int offset, int whence); -int fz_read(fz_stream *stm, unsigned char *buf, int len); -void fz_read_line(fz_stream *stm, char *buf, int max); -fz_buffer *fz_read_all(fz_stream *stm, int initial); +/* + fz_read: Read from a stream into a given data block. -static inline int fz_read_byte(fz_stream *stm) -{ - if (stm->rp == stm->wp) - { - fz_fill_buffer(stm); - return stm->rp < stm->wp ? *stm->rp++ : EOF; - } - return *stm->rp++; -} + stm: The stream to read from. -static inline int fz_peek_byte(fz_stream *stm) -{ - if (stm->rp == stm->wp) - { - fz_fill_buffer(stm); - return stm->rp < stm->wp ? *stm->rp : EOF; - } - return *stm->rp; -} + data: The data block to read into. -static inline void fz_unread_byte(fz_stream *stm) -{ - if (stm->rp > stm->bp) - stm->rp--; -} + len: The length of the data block (in bytes). -static inline int fz_is_eof(fz_stream *stm) -{ - if (stm->rp == stm->wp) - { - if (stm->eof) - return 1; - return fz_peek_byte(stm) == EOF; - } - return 0; -} + Returns the number of bytes read. May throw exceptions. +*/ +int fz_read(fz_stream *stm, unsigned char *data, int len); -static inline unsigned int fz_read_bits(fz_stream *stm, int n) -{ - unsigned int x; +/* + fz_read_all: Read all of a stream into a buffer. - if (n <= stm->avail) - { - stm->avail -= n; - x = (stm->bits >> stm->avail) & ((1 << n) - 1); - } - else - { - x = stm->bits & ((1 << stm->avail) - 1); - n -= stm->avail; - stm->avail = 0; + stm: The stream to read from - while (n > 8) - { - x = (x << 8) | fz_read_byte(stm); - n -= 8; - } + initial: Suggested initial size for the buffer. - if (n > 0) - { - stm->bits = fz_read_byte(stm); - stm->avail = 8 - n; - x = (x << n) | (stm->bits >> stm->avail); - } - } + Returns a buffer created from reading from the stream. May throw + exceptions on failure to allocate. +*/ +fz_buffer *fz_read_all(fz_stream *stm, int initial); - return x; -} +/* + Bitmaps have 1 bit per component. Only used for creating halftoned + versions of contone buffers, and saving out. Samples are stored msb + first, akin to pbms. +*/ +typedef struct fz_bitmap_s fz_bitmap; -static inline void fz_sync_bits(fz_stream *stm) -{ - stm->avail = 0; -} +/* + fz_keep_bitmap: Take a reference to a bitmap. -static inline int fz_is_eof_bits(fz_stream *stm) -{ - return fz_is_eof(stm) && (stm->avail == 0 || stm->bits == EOF); -} + bit: The bitmap to increment the reference for. + + Returns bit. Does not throw exceptions. +*/ +fz_bitmap *fz_keep_bitmap(fz_context *ctx, fz_bitmap *bit); /* - * Data filters. - */ + fz_drop_bitmap: Drop a reference and free a bitmap. -fz_stream *fz_open_copy(fz_stream *chain); -fz_stream *fz_open_null(fz_stream *chain, int len); -fz_stream *fz_open_arc4(fz_stream *chain, unsigned char *key, unsigned keylen); -fz_stream *fz_open_aesd(fz_stream *chain, unsigned char *key, unsigned keylen); -fz_stream *fz_open_a85d(fz_stream *chain); -fz_stream *fz_open_ahxd(fz_stream *chain); -fz_stream *fz_open_rld(fz_stream *chain); -fz_stream *fz_open_dctd(fz_stream *chain, int color_transform); -fz_stream *fz_open_faxd(fz_stream *chain, - int k, int end_of_line, int encoded_byte_align, - int columns, int rows, int end_of_block, int black_is_1); -fz_stream *fz_open_flated(fz_stream *chain); -fz_stream *fz_open_lzwd(fz_stream *chain, int early_change); -fz_stream *fz_open_predict(fz_stream *chain, int predictor, int columns, int colors, int bpc); -fz_stream *fz_open_jbig2d(fz_stream *chain, fz_buffer *global); - -/* - * Resources and other graphics related objects. - */ + Decrement the reference count for the bitmap. When no + references remain the pixmap will be freed. -enum { FZ_MAX_COLORS = 32 }; + Does not throw exceptions. +*/ +void fz_drop_bitmap(fz_context *ctx, fz_bitmap *bit); -int fz_find_blendmode(char *name); -char *fz_blendmode_name(int blendmode); +/* + An fz_colorspace object represents an abstract colorspace. While + this should be treated as a black box by callers of the library at + this stage, know that it encapsulates knowledge of how to convert + colors to and from the colorspace, any lookup tables generated, the + number of components in the colorspace etc. +*/ +typedef struct fz_colorspace_s fz_colorspace; /* - * Pixmaps have n components per pixel. the last is always alpha. - * premultiplied alpha when rendering, but non-premultiplied for colorspace - * conversions and rescaling. - */ + fz_find_device_colorspace: Find a standard colorspace based upon + it's name. +*/ +fz_colorspace *fz_find_device_colorspace(fz_context *ctx, char *name); +/* + fz_device_gray: Abstract colorspace representing device specific + gray. +*/ +extern fz_colorspace *fz_device_gray; + +/* + fz_device_rgb: Abstract colorspace representing device specific + rgb. +*/ +extern fz_colorspace *fz_device_rgb; + +/* + fz_device_bgr: Abstract colorspace representing device specific + bgr. +*/ +extern fz_colorspace *fz_device_bgr; + +/* + fz_device_cmyk: Abstract colorspace representing device specific + CMYK. +*/ +extern fz_colorspace *fz_device_cmyk; + +/* + Pixmaps represent a set of pixels for a 2 dimensional region of a + plane. Each pixel has n components per pixel, the last of which is + always alpha. The data is in premultiplied alpha when rendering, but + non-premultiplied for colorspace conversions and rescaling. +*/ typedef struct fz_pixmap_s fz_pixmap; -typedef struct fz_colorspace_s fz_colorspace; -struct fz_pixmap_s -{ - fz_storable storable; - int x, y, w, h, n; - fz_pixmap *mask; /* explicit soft/image mask */ - int interpolate; - int xres, yres; - fz_colorspace *colorspace; - unsigned char *samples; - int free_samples; -}; +/* + fz_pixmap_bbox: Return a bounding box for a pixmap. -fz_bbox fz_bound_pixmap(fz_pixmap *pix); + Returns an exact bounding box for the supplied pixmap. +*/ +fz_bbox fz_pixmap_bbox(fz_context *ctx, fz_pixmap *pix); -fz_pixmap *fz_new_pixmap_with_data(fz_context *ctx, fz_colorspace *colorspace, int w, int h, unsigned char *samples); -fz_pixmap *fz_new_pixmap_with_rect(fz_context *ctx, fz_colorspace *, fz_bbox bbox); -fz_pixmap *fz_new_pixmap_with_rect_and_data(fz_context *ctx, fz_colorspace *, fz_bbox bbox, unsigned char *samples); -fz_pixmap *fz_new_pixmap(fz_context *ctx, fz_colorspace *, int w, int h); -fz_pixmap *fz_keep_pixmap(fz_context *ctx, fz_pixmap *pix); -void fz_drop_pixmap(fz_context *ctx, fz_pixmap *pix); -void fz_free_pixmap_imp(fz_context *ctx, fz_storable *pix); -void fz_clear_pixmap(fz_context *ctx, fz_pixmap *pix); -void fz_clear_pixmap_with_value(fz_context *ctx, fz_pixmap *pix, int value); -void fz_clear_pixmap_rect_with_value(fz_context *ctx, fz_pixmap *pix, int value, fz_bbox r); -void fz_copy_pixmap_rect(fz_context *ctx, fz_pixmap *dest, fz_pixmap *src, fz_bbox r); -void fz_premultiply_pixmap(fz_context *ctx, fz_pixmap *pix); -void fz_unmultiply_pixmap(fz_context *ctx, fz_pixmap *pix); -fz_pixmap *fz_alpha_from_gray(fz_context *ctx, fz_pixmap *gray, int luminosity); -void fz_invert_pixmap(fz_context *ctx, fz_pixmap *pix); -void fz_gamma_pixmap(fz_context *ctx, fz_pixmap *pix, float gamma); -unsigned int fz_pixmap_size(fz_context *ctx, fz_pixmap *pix); +/* + fz_pixmap_width: Return the width of the pixmap in pixels. +*/ +int fz_pixmap_width(fz_context *ctx, fz_pixmap *pix); -fz_pixmap *fz_scale_pixmap(fz_context *ctx, fz_pixmap *src, float x, float y, float w, float h, fz_bbox *clip); +/* + fz_pixmap_height: Return the height of the pixmap in pixels. +*/ +int fz_pixmap_height(fz_context *ctx, fz_pixmap *pix); -void fz_write_pnm(fz_context *ctx, fz_pixmap *pixmap, char *filename); -void fz_write_pam(fz_context *ctx, fz_pixmap *pixmap, char *filename, int savealpha); -void fz_write_png(fz_context *ctx, fz_pixmap *pixmap, char *filename, int savealpha); +/* + fz_new_pixmap: Create a new pixmap, with it's origin at (0,0) + + cs: The colorspace to use for the pixmap, or NULL for an alpha + plane/mask. -fz_pixmap *fz_load_jpx(fz_context *ctx, unsigned char *data, int size, fz_colorspace *cs); -fz_pixmap *fz_load_jpeg(fz_context *doc, unsigned char *data, int size); -fz_pixmap *fz_load_png(fz_context *doc, unsigned char *data, int size); -fz_pixmap *fz_load_tiff(fz_context *doc, unsigned char *data, int size); + w: The width of the pixmap (in pixels) + + h: The height of the pixmap (in pixels) + + Returns a pointer to the new pixmap. Throws exception on failure to + allocate. +*/ +fz_pixmap *fz_new_pixmap(fz_context *ctx, fz_colorspace *cs, int w, int h); /* - * Bitmaps have 1 component per bit. Only used for creating halftoned versions - * of contone buffers, and saving out. Samples are stored msb first, akin to - * pbms. - */ + fz_new_pixmap_with_bbox: Create a pixmap of a given size, + location and pixel format. -typedef struct fz_bitmap_s fz_bitmap; + The bounding box specifies the size of the created pixmap and + where it will be located. The colorspace determines the number + of components per pixel. Alpha is always present. Pixmaps are + reference counted, so drop references using fz_drop_pixmap. -struct fz_bitmap_s -{ - int refs; - int w, h, stride, n; - unsigned char *samples; -}; + colorspace: Colorspace format used for the created pixmap. The + pixmap will keep a reference to the colorspace. -fz_bitmap *fz_new_bitmap(fz_context *ctx, int w, int h, int n); -fz_bitmap *fz_keep_bitmap(fz_context *ctx, fz_bitmap *bit); -void fz_clear_bitmap(fz_context *ctx, fz_bitmap *bit); -void fz_drop_bitmap(fz_context *ctx, fz_bitmap *bit); + bbox: Bounding box specifying location/size of created pixmap. -void fz_write_pbm(fz_context *ctx, fz_bitmap *bitmap, char *filename); + Returns a pointer to the new pixmap. Throws exception on failure to + allocate. +*/ +fz_pixmap *fz_new_pixmap_with_bbox(fz_context *ctx, fz_colorspace *colorspace, fz_bbox bbox); /* - * A halftone is a set of threshold tiles, one per component. Each threshold - * tile is a pixmap, possibly of varying sizes and phases. - */ + fz_new_pixmap_with_data: Create a new pixmap, with it's origin at + (0,0) using the supplied data block. -typedef struct fz_halftone_s fz_halftone; + cs: The colorspace to use for the pixmap, or NULL for an alpha + plane/mask. -struct fz_halftone_s -{ - int refs; - int n; - fz_pixmap *comp[1]; -}; + w: The width of the pixmap (in pixels) -fz_halftone *fz_new_halftone(fz_context *ctx, int num_comps); -fz_halftone *fz_get_default_halftone(fz_context *ctx, int num_comps); -fz_halftone *fz_keep_halftone(fz_context *ctx, fz_halftone *half); -void fz_drop_halftone(fz_context *ctx, fz_halftone *half); + h: The height of the pixmap (in pixels) -fz_bitmap *fz_halftone_pixmap(fz_context *ctx, fz_pixmap *pix, fz_halftone *ht); + samples: The data block to keep the samples in. + + Returns a pointer to the new pixmap. Throws exception on failure to + allocate. +*/ +fz_pixmap *fz_new_pixmap_with_data(fz_context *ctx, fz_colorspace *colorspace, int w, int h, unsigned char *samples); /* - * Colorspace resources. - */ + fz_new_pixmap_with_bbox_and_data: Create a pixmap of a given size, + location and pixel format, using the supplied data block. -extern fz_colorspace *fz_device_gray; -extern fz_colorspace *fz_device_rgb; -extern fz_colorspace *fz_device_bgr; -extern fz_colorspace *fz_device_cmyk; + The bounding box specifies the size of the created pixmap and + where it will be located. The colorspace determines the number + of components per pixel. Alpha is always present. Pixmaps are + reference counted, so drop references using fz_drop_pixmap. -struct fz_colorspace_s -{ - fz_storable storable; - unsigned int size; - char name[16]; - int n; - void (*to_rgb)(fz_context *ctx, fz_colorspace *, float *src, float *rgb); - void (*from_rgb)(fz_context *ctx, fz_colorspace *, float *rgb, float *dst); - void (*free_data)(fz_context *Ctx, fz_colorspace *); - void *data; -}; + colorspace: Colorspace format used for the created pixmap. The + pixmap will keep a reference to the colorspace. -fz_colorspace *fz_new_colorspace(fz_context *ctx, char *name, int n); -fz_colorspace *fz_keep_colorspace(fz_context *ctx, fz_colorspace *colorspace); -void fz_drop_colorspace(fz_context *ctx, fz_colorspace *colorspace); -void fz_free_colorspace_imp(fz_context *ctx, fz_storable *colorspace); + bbox: Bounding box specifying location/size of created pixmap. -void fz_convert_color(fz_context *ctx, fz_colorspace *srcs, float *srcv, fz_colorspace *dsts, float *dstv); -void fz_convert_pixmap(fz_context *ctx, fz_pixmap *src, fz_pixmap *dst); + samples: The data block to keep the samples in. -fz_colorspace *fz_find_device_colorspace(char *name); + Returns a pointer to the new pixmap. Throws exception on failure to + allocate. +*/ +fz_pixmap *fz_new_pixmap_with_bbox_and_data(fz_context *ctx, fz_colorspace *colorspace, fz_bbox bbox, unsigned char *samples); /* - * Fonts come in two variants: - * Regular fonts are handled by FreeType. - * Type 3 fonts have callbacks to the interpreter. - */ + fz_keep_pixmap: Take a reference to a pixmap. -typedef struct fz_device_s fz_device; + pix: The pixmap to increment the reference for. -typedef struct fz_font_s fz_font; -char *ft_error_string(int err); + Returns pix. Does not throw exceptions. +*/ +fz_pixmap *fz_keep_pixmap(fz_context *ctx, fz_pixmap *pix); -struct fz_font_s -{ - int refs; - char name[32]; - - void *ft_face; /* has an FT_Face if used */ - int ft_substitute; /* ... substitute metrics */ - int ft_bold; /* ... synthesize bold */ - int ft_italic; /* ... synthesize italic */ - int ft_hint; /* ... force hinting for DynaLab fonts */ - - /* origin of font data */ - char *ft_file; - unsigned char *ft_data; - int ft_size; - - fz_matrix t3matrix; - fz_obj *t3resources; - fz_buffer **t3procs; /* has 256 entries if used */ - float *t3widths; /* has 256 entries if used */ - char *t3flags; /* has 256 entries if used */ - void *t3doc; /* a pdf_document for the callback */ - void (*t3run)(void *doc, fz_obj *resources, fz_buffer *contents, fz_device *dev, fz_matrix ctm, void *gstate); - - fz_rect bbox; /* font bbox is used only for t3 fonts */ - - /* per glyph bounding box cache */ - int use_glyph_bbox; - int bbox_count; - fz_rect *bbox_table; - - /* substitute metrics */ - int width_count; - int *width_table; /* in 1000 units */ -}; +/* + fz_drop_pixmap: Drop a reference and free a pixmap. -void fz_new_font_context(fz_context *ctx); -fz_font_context *fz_keep_font_context(fz_context *ctx); -void fz_drop_font_context(fz_context *ctx); + Decrement the reference count for the pixmap. When no + references remain the pixmap will be freed. -fz_font *fz_new_type3_font(fz_context *ctx, char *name, fz_matrix matrix); + Does not throw exceptions. +*/ +void fz_drop_pixmap(fz_context *ctx, fz_pixmap *pix); -fz_font *fz_new_font_from_memory(fz_context *ctx, unsigned char *data, int len, int index, int use_glyph_bbox); -fz_font *fz_new_font_from_file(fz_context *ctx, char *path, int index, int use_glyph_bbox); +/* + fz_pixmap_colorspace: Return the colorspace of a pixmap -fz_font *fz_keep_font(fz_context *ctx, fz_font *font); -void fz_drop_font(fz_context *ctx, fz_font *font); + Returns colorspace. Does not throw exceptions. +*/ +fz_colorspace *fz_pixmap_colorspace(fz_context *ctx, fz_pixmap *pix); -void fz_debug_font(fz_context *ctx, fz_font *font); +/* + fz_pixmap_components: Return the number of components in a pixmap. -void fz_set_font_bbox(fz_context *ctx, fz_font *font, float xmin, float ymin, float xmax, float ymax); -fz_rect fz_bound_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm); -int fz_glyph_cacheable(fz_context *ctx, fz_font *font, int gid); + Returns the number of components. Does not throw exceptions. +*/ +int fz_pixmap_components(fz_context *ctx, fz_pixmap *pix); /* - * Vector path buffer. - * It can be stroked and dashed, or be filled. - * It has a fill rule (nonzero or even_odd). - * - * When rendering, they are flattened, stroked and dashed straight - * into the Global Edge List. - */ + fz_pixmap_samples: Returns a pointer to the pixel data of a pixmap. -typedef struct fz_path_s fz_path; -typedef struct fz_stroke_state_s fz_stroke_state; + Returns the pointer. Does not throw exceptions. +*/ +unsigned char *fz_pixmap_samples(fz_context *ctx, fz_pixmap *pix); -typedef union fz_path_item_s fz_path_item; +/* + fz_clear_pixmap_with_value: Clears a pixmap with the given value. -typedef enum fz_path_item_kind_e -{ - FZ_MOVETO, - FZ_LINETO, - FZ_CURVETO, - FZ_CLOSE_PATH -} fz_path_item_kind; + pix: The pixmap to clear. -typedef enum fz_linecap_e -{ - FZ_LINECAP_BUTT = 0, - FZ_LINECAP_ROUND = 1, - FZ_LINECAP_SQUARE = 2, - FZ_LINECAP_TRIANGLE = 3 -} fz_linecap; + value: Values in the range 0 to 255 are valid. Each component + sample for each pixel in the pixmap will be set to this value, + while alpha will always be set to 255 (non-transparent). -typedef enum fz_linejoin_e -{ - FZ_LINEJOIN_MITER = 0, - FZ_LINEJOIN_ROUND = 1, - FZ_LINEJOIN_BEVEL = 2, - FZ_LINEJOIN_MITER_XPS = 3 -} fz_linejoin; + Does not throw exceptions. +*/ +void fz_clear_pixmap_with_value(fz_context *ctx, fz_pixmap *pix, int value); -union fz_path_item_s -{ - fz_path_item_kind k; - float v; -}; +/* + fz_clear_pixmap_with_value: Sets all components (including alpha) of + all pixels in a pixmap to 0. -struct fz_path_s -{ - int len, cap; - fz_path_item *items; - int last; -}; + pix: The pixmap to clear. -struct fz_stroke_state_s -{ - fz_linecap start_cap, dash_cap, end_cap; - fz_linejoin linejoin; - float linewidth; - float miterlimit; - float dash_phase; - int dash_len; - float dash_list[32]; -}; + Does not throw exceptions. +*/ +void fz_clear_pixmap(fz_context *ctx, fz_pixmap *pix); -fz_path *fz_new_path(fz_context *ctx); -void fz_moveto(fz_context*, fz_path*, float x, float y); -void fz_lineto(fz_context*, fz_path*, float x, float y); -void fz_curveto(fz_context*,fz_path*, float, float, float, float, float, float); -void fz_curvetov(fz_context*,fz_path*, float, float, float, float); -void fz_curvetoy(fz_context*,fz_path*, float, float, float, float); -void fz_closepath(fz_context*,fz_path*); -void fz_free_path(fz_context *ctx, fz_path *path); +/* + fz_invert_pixmap: Invert all the pixels in a pixmap. All components + of all pixels are inverted (except alpha, which is unchanged). -void fz_transform_path(fz_context *ctx, fz_path *path, fz_matrix transform); + Does not throw exceptions. +*/ +void fz_invert_pixmap(fz_context *ctx, fz_pixmap *pix); -fz_path *fz_clone_path(fz_context *ctx, fz_path *old); +/* + fz_invert_pixmap: Invert all the pixels in a given rectangle of a + pixmap. All components of all pixels in the rectangle are inverted + (except alpha, which is unchanged). -fz_rect fz_bound_path(fz_context *ctx, fz_path *path, fz_stroke_state *stroke, fz_matrix ctm); -void fz_debug_path(fz_context *ctx, fz_path *, int indent); + Does not throw exceptions. +*/ +void fz_invert_pixmap_rect(fz_pixmap *image, fz_bbox rect); /* - * Glyph cache - */ + fz_gamma_pixmap: Apply gamma correction to a pixmap. All components + of all pixels are modified (except alpha, which is unchanged). -void fz_new_glyph_cache_context(fz_context *ctx); -fz_glyph_cache *fz_keep_glyph_cache(fz_context *ctx); -void fz_drop_glyph_cache_context(fz_context *ctx); -void fz_purge_glyph_cache(fz_context *ctx); - -fz_pixmap *fz_render_ft_glyph(fz_context *ctx, fz_font *font, int cid, fz_matrix trm); -fz_pixmap *fz_render_t3_glyph(fz_context *ctx, fz_font *font, int cid, fz_matrix trm, fz_colorspace *model); -fz_pixmap *fz_render_ft_stroked_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm, fz_matrix ctm, fz_stroke_state *state); -fz_pixmap *fz_render_glyph(fz_context *ctx, fz_font*, int, fz_matrix, fz_colorspace *model); -fz_pixmap *fz_render_stroked_glyph(fz_context *ctx, fz_font*, int, fz_matrix, fz_matrix, fz_stroke_state *stroke); -void fz_render_t3_glyph_direct(fz_context *ctx, fz_device *dev, fz_font *font, int gid, fz_matrix trm, void *gstate); - -/* - * Text buffer. - * - * The trm field contains the a, b, c and d coefficients. - * The e and f coefficients come from the individual elements, - * together they form the transform matrix for the glyph. - * - * Glyphs are referenced by glyph ID. - * The Unicode text equivalent is kept in a separate array - * with indexes into the glyph array. - */ + gamma: The gamma value to apply; 1.0 for no change. -typedef struct fz_text_s fz_text; -typedef struct fz_text_item_s fz_text_item; + Does not throw exceptions. +*/ +void fz_gamma_pixmap(fz_context *ctx, fz_pixmap *pix, float gamma); -struct fz_text_item_s -{ - float x, y; - int gid; /* -1 for one gid to many ucs mappings */ - int ucs; /* -1 for one ucs to many gid mappings */ -}; +/* + fz_unmultiply_pixmap: Convert a pixmap from premultiplied to + non-premultiplied format. -struct fz_text_s -{ - fz_font *font; - fz_matrix trm; - int wmode; - int len, cap; - fz_text_item *items; -}; + Does not throw exceptions. +*/ +void fz_unmultiply_pixmap(fz_context *ctx, fz_pixmap *pix); + +/* + fz_convert_pixmap: Convert from one pixmap to another (assumed to be + the same size, but possibly with a different colorspace). + + dst: the source pixmap. -fz_text *fz_new_text(fz_context *ctx, fz_font *face, fz_matrix trm, int wmode); -void fz_add_text(fz_context *ctx, fz_text *text, int gid, int ucs, float x, float y); -void fz_free_text(fz_context *ctx, fz_text *text); -fz_rect fz_bound_text(fz_context *ctx, fz_text *text, fz_matrix ctm); -fz_text *fz_clone_text(fz_context *ctx, fz_text *old); -void fz_debug_text(fz_context *ctx, fz_text*, int indent); + src: the destination pixmap. +*/ +void fz_convert_pixmap(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src); /* - * The shading code uses gouraud shaded triangle meshes. - */ + fz_write_pixmap: Save a pixmap out. -enum -{ - FZ_LINEAR, - FZ_RADIAL, - FZ_MESH, -}; + name: The prefix for the name of the pixmap. The pixmap will be saved + as "name.png" if the pixmap is RGB or Greyscale, "name.pam" otherwise. -typedef struct fz_shade_s fz_shade; + rgb: If non zero, the pixmap is converted to rgb (if possible) before + saving. +*/ +void fz_write_pixmap(fz_context *ctx, fz_pixmap *img, char *name, int rgb); -struct fz_shade_s -{ - fz_storable storable; +/* + fz_write_pnm: Save a pixmap as a pnm - fz_rect bbox; /* can be fz_infinite_rect */ - fz_colorspace *colorspace; + filename: The filename to save as (including extension). +*/ +void fz_write_pnm(fz_context *ctx, fz_pixmap *pixmap, char *filename); - fz_matrix matrix; /* matrix from pattern dict */ - int use_background; /* background color for fills but not 'sh' */ - float background[FZ_MAX_COLORS]; +/* + fz_write_pam: Save a pixmap as a pam - int use_function; - float function[256][FZ_MAX_COLORS + 1]; + filename: The filename to save as (including extension). +*/ +void fz_write_pam(fz_context *ctx, fz_pixmap *pixmap, char *filename, int savealpha); - int type; /* linear, radial, mesh */ - int extend[2]; +/* + fz_write_png: Save a pixmap as a png - int mesh_len; - int mesh_cap; - float *mesh; /* [x y 0], [x y r], [x y t] or [x y c1 ... cn] */ -}; + filename: The filename to save as (including extension). +*/ +void fz_write_png(fz_context *ctx, fz_pixmap *pixmap, char *filename, int savealpha); + +/* + fz_write_pbm: Save a bitmap as a pbm + + filename: The filename to save as (including extension). +*/ +void fz_write_pbm(fz_context *ctx, fz_bitmap *bitmap, char *filename); -fz_shade *fz_keep_shade(fz_context *ctx, fz_shade *shade); -void fz_drop_shade(fz_context *ctx, fz_shade *shade); -void fz_free_shade_imp(fz_context *ctx, fz_storable *shade); -void fz_debug_shade(fz_context *ctx, fz_shade *shade); +/* + fz_md5_pixmap: Return the md5 digest for a pixmap -fz_rect fz_bound_shade(fz_context *ctx, fz_shade *shade, fz_matrix ctm); -void fz_paint_shade(fz_context *ctx, fz_shade *shade, fz_matrix ctm, fz_pixmap *dest, fz_bbox bbox); + filename: The filename to save as (including extension). +*/ +void fz_md5_pixmap(fz_pixmap *pixmap, unsigned char digest[16]); /* - * Scan converter + Images are storable objects from which we can obtain fz_pixmaps. + These may be implemented as simple wrappers around a pixmap, or as + more complex things that decode at different subsample settings on + demand. */ +typedef struct fz_image_s fz_image; -int fz_get_aa_level(fz_context *ctx); -void fz_set_aa_level(fz_context *ctx, int bits); +/* + fz_image_to_pixmap: Called to get a handle to a pixmap from an image. -typedef struct fz_gel_s fz_gel; + image: The image to retrieve a pixmap from. -fz_gel *fz_new_gel(fz_context *ctx); -void fz_insert_gel(fz_gel *gel, float x0, float y0, float x1, float y1); -void fz_reset_gel(fz_gel *gel, fz_bbox clip); -void fz_sort_gel(fz_gel *gel); -fz_bbox fz_bound_gel(fz_gel *gel); -void fz_free_gel(fz_gel *gel); -int fz_is_rect_gel(fz_gel *gel); + w: The desired width (in pixels). This may be completely ignored, but + may serve as an indication of a suitable subsample factor to use for + image types that support this. -void fz_scan_convert(fz_gel *gel, int eofill, fz_bbox clip, fz_pixmap *pix, unsigned char *colorbv); + h: The desired height (in pixels). This may be completely ignored, but + may serve as an indication of a suitable subsample factor to use for + image types that support this. -void fz_flatten_fill_path(fz_gel *gel, fz_path *path, fz_matrix ctm, float flatness); -void fz_flatten_stroke_path(fz_gel *gel, fz_path *path, fz_stroke_state *stroke, fz_matrix ctm, float flatness, float linewidth); -void fz_flatten_dash_path(fz_gel *gel, fz_path *path, fz_stroke_state *stroke, fz_matrix ctm, float flatness, float linewidth); + Returns a non NULL pixmap pointer. May throw exceptions. +*/ +fz_pixmap *fz_image_to_pixmap(fz_context *ctx, fz_image *image, int w, int h); /* - * The device interface. - */ + fz_drop_image: Drop a reference to an image. -enum -{ - /* Hints */ - FZ_IGNORE_IMAGE = 1, - FZ_IGNORE_SHADE = 2, - - /* Flags */ - FZ_DEVFLAG_MASK = 1, - FZ_DEVFLAG_COLOR = 2, - FZ_DEVFLAG_UNCACHEABLE = 4, - FZ_DEVFLAG_FILLCOLOR_UNDEFINED = 8, - FZ_DEVFLAG_STROKECOLOR_UNDEFINED = 16, - FZ_DEVFLAG_STARTCAP_UNDEFINED = 32, - FZ_DEVFLAG_DASHCAP_UNDEFINED = 64, - FZ_DEVFLAG_ENDCAP_UNDEFINED = 128, - FZ_DEVFLAG_LINEJOIN_UNDEFINED = 256, - FZ_DEVFLAG_MITERLIMIT_UNDEFINED = 512, - FZ_DEVFLAG_LINEWIDTH_UNDEFINED = 1024, - /* Arguably we should have a bit for the dash pattern itself being - * undefined, but that causes problems; do we assume that it should - * always be set to non-dashing at the start of every glyph? */ -}; + image: The image to drop a reference to. +*/ +void fz_drop_image(fz_context *ctx, fz_image *image); -struct fz_device_s -{ - int hints; - int flags; +/* + fz_keep_image: Increment the reference count of an image. - void *user; - void (*free_user)(fz_device *); - fz_context *ctx; - - void (*fill_path)(fz_device *, fz_path *, int even_odd, fz_matrix, fz_colorspace *, float *color, float alpha); - void (*stroke_path)(fz_device *, fz_path *, fz_stroke_state *, fz_matrix, fz_colorspace *, float *color, float alpha); - void (*clip_path)(fz_device *, fz_path *, fz_rect *rect, int even_odd, fz_matrix); - void (*clip_stroke_path)(fz_device *, fz_path *, fz_rect *rect, fz_stroke_state *, fz_matrix); - - void (*fill_text)(fz_device *, fz_text *, fz_matrix, fz_colorspace *, float *color, float alpha); - void (*stroke_text)(fz_device *, fz_text *, fz_stroke_state *, fz_matrix, fz_colorspace *, float *color, float alpha); - void (*clip_text)(fz_device *, fz_text *, fz_matrix, int accumulate); - void (*clip_stroke_text)(fz_device *, fz_text *, fz_stroke_state *, fz_matrix); - void (*ignore_text)(fz_device *, fz_text *, fz_matrix); - - void (*fill_shade)(fz_device *, fz_shade *shd, fz_matrix ctm, float alpha); - void (*fill_image)(fz_device *, fz_pixmap *img, fz_matrix ctm, float alpha); - void (*fill_image_mask)(fz_device *, fz_pixmap *img, fz_matrix ctm, fz_colorspace *, float *color, float alpha); - void (*clip_image_mask)(fz_device *, fz_pixmap *img, fz_rect *rect, fz_matrix ctm); - - void (*pop_clip)(fz_device *); - - void (*begin_mask)(fz_device *, fz_rect, int luminosity, fz_colorspace *, float *bc); - void (*end_mask)(fz_device *); - void (*begin_group)(fz_device *, fz_rect, int isolated, int knockout, int blendmode, float alpha); - void (*end_group)(fz_device *); - - void (*begin_tile)(fz_device *, fz_rect area, fz_rect view, float xstep, float ystep, fz_matrix ctm); - void (*end_tile)(fz_device *); -}; + image: The image to take a reference to. -void fz_fill_path(fz_device *dev, fz_path *path, int even_odd, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha); -void fz_stroke_path(fz_device *dev, fz_path *path, fz_stroke_state *stroke, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha); -void fz_clip_path(fz_device *dev, fz_path *path, fz_rect *rect, int even_odd, fz_matrix ctm); -void fz_clip_stroke_path(fz_device *dev, fz_path *path, fz_rect *rect, fz_stroke_state *stroke, fz_matrix ctm); -void fz_fill_text(fz_device *dev, fz_text *text, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha); -void fz_stroke_text(fz_device *dev, fz_text *text, fz_stroke_state *stroke, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha); -void fz_clip_text(fz_device *dev, fz_text *text, fz_matrix ctm, int accumulate); -void fz_clip_stroke_text(fz_device *dev, fz_text *text, fz_stroke_state *stroke, fz_matrix ctm); -void fz_ignore_text(fz_device *dev, fz_text *text, fz_matrix ctm); -void fz_pop_clip(fz_device *dev); -void fz_fill_shade(fz_device *dev, fz_shade *shade, fz_matrix ctm, float alpha); -void fz_fill_image(fz_device *dev, fz_pixmap *image, fz_matrix ctm, float alpha); -void fz_fill_image_mask(fz_device *dev, fz_pixmap *image, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha); -void fz_clip_image_mask(fz_device *dev, fz_pixmap *image, fz_rect *rect, fz_matrix ctm); -void fz_begin_mask(fz_device *dev, fz_rect area, int luminosity, fz_colorspace *colorspace, float *bc); -void fz_end_mask(fz_device *dev); -void fz_begin_group(fz_device *dev, fz_rect area, int isolated, int knockout, int blendmode, float alpha); -void fz_end_group(fz_device *dev); -void fz_begin_tile(fz_device *dev, fz_rect area, fz_rect view, float xstep, float ystep, fz_matrix ctm); -void fz_end_tile(fz_device *dev); - -fz_device *fz_new_device(fz_context *ctx, void *user); + Returns a pointer to the image. +*/ +fz_image *fz_keep_image(fz_context *ctx, fz_image *image); + +/* + A halftone is a set of threshold tiles, one per component. Each + threshold tile is a pixmap, possibly of varying sizes and phases. + Currently, we only provide one 'default' halftone tile for operating + on 1 component plus alpha pixmaps (where the alpha is ignored). This + is signified by an fz_halftone pointer to NULL. +*/ +typedef struct fz_halftone_s fz_halftone; + +/* + fz_halftone_pixmap: Make a bitmap from a pixmap and a halftone. + + pix: The pixmap to generate from. Currently must be a single color + component + alpha (where the alpha is assumed to be solid). + + ht: The halftone to use. NULL implies the default halftone. + + Returns the resultant bitmap. Throws exceptions in the case of + failure to allocate. +*/ +fz_bitmap *fz_halftone_pixmap(fz_context *ctx, fz_pixmap *pix, fz_halftone *ht); + +/* + An abstract font handle. Currently there are no public API functions + for handling these. +*/ +typedef struct fz_font_s fz_font; + +/* + The different format handlers (pdf, xps etc) interpret pages to a + device. These devices can then process the stream of calls they + recieve in various ways: + The trace device outputs debugging information for the calls. + The draw device will render them. + The list device stores them in a list to play back later. + The text device performs text extraction and searching. + The bbox device calculates the bounding box for the page. + Other devices can (and will) be written in future. +*/ +typedef struct fz_device_s fz_device; + +/* + fz_free_device: Free a devices of any type and its resources. +*/ void fz_free_device(fz_device *dev); +/* + fz_new_trace_device: Create a device to print a debug trace of + all device calls. +*/ fz_device *fz_new_trace_device(fz_context *ctx); + +/* + fz_new_bbox_device: Create a device to compute the bounding + box of all marks on a page. + + The returned bounding box will be the union of all bounding + boxes of all objects on a page. +*/ fz_device *fz_new_bbox_device(fz_context *ctx, fz_bbox *bboxp); + +/* + fz_new_draw_device: Create a device to draw on a pixmap. + + dest: Target pixmap for the draw device. See fz_new_pixmap* + for how to obtain a pixmap. The pixmap is not cleared by the + draw device, see fz_clear_pixmap* for how to clear it prior to + calling fz_new_draw_device. Free the device by calling + fz_free_device. +*/ fz_device *fz_new_draw_device(fz_context *ctx, fz_pixmap *dest); -fz_device *fz_new_draw_device_type3(fz_context *ctx, fz_pixmap *dest); /* - * Text extraction device + Text extraction device: Used for searching, format conversion etc. */ -typedef struct fz_text_span_s fz_text_span; +typedef struct fz_text_style_s fz_text_style; typedef struct fz_text_char_s fz_text_char; +typedef struct fz_text_span_s fz_text_span; +typedef struct fz_text_line_s fz_text_line; +typedef struct fz_text_block_s fz_text_block; + +typedef struct fz_text_sheet_s fz_text_sheet; +typedef struct fz_text_page_s fz_text_page; + +struct fz_text_style_s +{ + int id; + fz_font *font; + float size; + int wmode; + int script; + /* etc... */ + fz_text_style *next; +}; + +struct fz_text_sheet_s +{ + int maxid; + fz_text_style *style; +}; struct fz_text_char_s { + fz_rect bbox; int c; - fz_bbox bbox; }; struct fz_text_span_s { - fz_font *font; - float size; - int wmode; + fz_rect bbox; int len, cap; fz_text_char *text; - fz_text_span *next; - int eol; + fz_text_style *style; }; -fz_text_span *fz_new_text_span(fz_context *ctx); -void fz_free_text_span(fz_context *ctx, fz_text_span *line); -void fz_debug_text_span(fz_text_span *line); -void fz_debug_text_span_xml(fz_text_span *span); +struct fz_text_line_s +{ + fz_rect bbox; + int len, cap; + fz_text_span *spans; +}; -fz_device *fz_new_text_device(fz_context *ctx, fz_text_span *text); +struct fz_text_block_s +{ + fz_rect bbox; + int len, cap; + fz_text_line *lines; +}; + +struct fz_text_page_s +{ + fz_rect mediabox; + int len, cap; + fz_text_block *blocks; +}; + +/* + fz_new_text_device: Create a device to extract the text on a page. + + Gather and sort the text on a page into spans of uniform style, + arranged into lines and blocks by reading order. The reading order + is determined by various heuristics, so may not be accurate. +*/ +fz_device *fz_new_text_device(fz_context *ctx, fz_text_sheet *sheet, fz_text_page *page); + +/* + fz_new_text_sheet: Create an empty style sheet. + + The style sheet is filled out by the text device, creating + one style for each unique font, color, size combination that + is used. +*/ +fz_text_sheet *fz_new_text_sheet(fz_context *ctx); +void fz_free_text_sheet(fz_context *ctx, fz_text_sheet *sheet); + +/* + fz_new_text_page: Create an empty text page. + + The text page is filled out by the text device to contain the blocks, + lines and spans of text on the page. +*/ +fz_text_page *fz_new_text_page(fz_context *ctx, fz_rect mediabox); +void fz_free_text_page(fz_context *ctx, fz_text_page *page); + +void fz_print_text_sheet(fz_context *ctx, FILE *out, fz_text_sheet *sheet); +void fz_print_text_page_html(fz_context *ctx, FILE *out, fz_text_page *page); +void fz_print_text_page_xml(fz_context *ctx, FILE *out, fz_text_page *page); +void fz_print_text_page(fz_context *ctx, FILE *out, fz_text_page *page); /* * Cookie support - simple communication channel between app/library. @@ -1494,6 +1583,40 @@ fz_device *fz_new_text_device(fz_context *ctx, fz_text_span *text); typedef struct fz_cookie_s fz_cookie; +/* + Provide two-way communication between application and library. + Intended for multi-threaded applications where one thread is + rendering pages and another thread wants read progress + feedback or abort a job that takes a long time to finish. The + communication is unsynchronized without locking. + + abort: The appliation should set this field to 0 before + calling fz_run_page to render a page. At any point when the + page is being rendered the application my set this field to 1 + which will cause the rendering to finish soon. This field is + checked periodically when the page is rendered, but exactly + when is not known, therefore there is no upper bound on + exactly when the the rendering will abort. If the application + did not provide a set of locks to fz_new_context, it must also + await the completion of fz_run_page before issuing another + call to fz_run_page. Note that once the application has set + this field to 1 after it called fz_run_page it may not change + the value again. + + progress: Communicates rendering progress back to the + application and is read only. Increments as a page is being + rendered. The value starts out at 0 and is limited to less + than or equal to progress_max, unless progress_max is -1. + + progress_max: Communicates the known upper bound of rendering + back to the application and is read only. The maximum value + that the progress field may take. If there is no known upper + bound on how long the rendering may take this value is -1 and + progress is not limited. Note that the value of progress_max + may change from -1 to a positive value once an upper bound is + known, so take this into consideration when comparing the + value of progress to that of progress_max. +*/ struct fz_cookie_s { int abort; @@ -1502,67 +1625,81 @@ struct fz_cookie_s }; /* - * Display list device -- record and play back device commands. - */ + Display list device -- record and play back device commands. +*/ +/* + fz_display_list is a list containing drawing commands (text, + images, etc.). The intent is two-fold: as a caching-mechanism + to reduce parsing of a page, and to be used as a data + structure in multi-threading where one thread parses the page + and another renders pages. + + Create a displaylist with fz_new_display_list, hand it over to + fz_new_list_device to have it populated, and later replay the + list (once or many times) by calling fz_run_display_list. When + the list is no longer needed free it with fz_free_display_list. +*/ typedef struct fz_display_list_s fz_display_list; +/* + fz_new_display_list: Create an empty display list. + + A display list contains drawing commands (text, images, etc.). + Use fz_new_list_device for populating the list. +*/ fz_display_list *fz_new_display_list(fz_context *ctx); -void fz_free_display_list(fz_context *ctx, fz_display_list *list); + +/* + fz_new_list_device: Create a rendering device for a display list. + + When the device is rendering a page it will populate the + display list with drawing commsnds (text, images, etc.). The + display list can later be reused to render a page many times + without having to re-interpret the page from the document file + for each rendering. Once the device is no longer needed, free + it with fz_free_device. + + list: A display list that the list device takes ownership of. +*/ fz_device *fz_new_list_device(fz_context *ctx, fz_display_list *list); -void fz_run_display_list(fz_display_list *list, fz_device *dev, fz_matrix ctm, fz_bbox area, fz_cookie *cookie); /* - * Plotting functions. - */ + fz_run_display_list: (Re)-run a display list through a device. -void fz_decode_tile(fz_pixmap *pix, float *decode); -void fz_decode_indexed_tile(fz_pixmap *pix, float *decode, int maxval); -void fz_unpack_tile(fz_pixmap *dst, unsigned char * restrict src, int n, int depth, int stride, int scale); + list: A display list, created by fz_new_display_list and + populated with objects from a page by running fz_run_page on a + device obtained from fz_new_list_device. -void fz_paint_solid_alpha(unsigned char * restrict dp, int w, int alpha); -void fz_paint_solid_color(unsigned char * restrict dp, int n, int w, unsigned char *color); + dev: Device obtained from fz_new_*_device. -void fz_paint_span(unsigned char * restrict dp, unsigned char * restrict sp, int n, int w, int alpha); -void fz_paint_span_with_color(unsigned char * restrict dp, unsigned char * restrict mp, int n, int w, unsigned char *color); + ctm: Transform to apply to display list contents. May include + for example scaling and rotation, see fz_scale, fz_rotate and + fz_concat. Set to fz_identity if no transformation is desired. -void fz_paint_image(fz_pixmap *dst, fz_bbox scissor, fz_pixmap *shape, fz_pixmap *img, fz_matrix ctm, int alpha); -void fz_paint_image_with_color(fz_pixmap *dst, fz_bbox scissor, fz_pixmap *shape, fz_pixmap *img, fz_matrix ctm, unsigned char *colorbv); + area: Only the part of the contents of the display list + visible within this area will be considered when the list is + run through the device. This does not imply for tile objects + contained in the display list. -void fz_paint_pixmap(fz_pixmap *dst, fz_pixmap *src, int alpha); -void fz_paint_pixmap_with_mask(fz_pixmap *dst, fz_pixmap *src, fz_pixmap *msk); -void fz_paint_pixmap_with_rect(fz_pixmap *dst, fz_pixmap *src, int alpha, fz_bbox bbox); + cookie: Communication mechanism between caller and library + running the page. Intended for multi-threaded applications, + while single-threaded applications set cookie to NULL. The + caller may abort an ongoing page run. Cookie also communicates + progress information back to the caller. The fields inside + cookie are continually updated while the page is being run. +*/ +void fz_run_display_list(fz_display_list *list, fz_device *dev, fz_matrix ctm, fz_bbox area, fz_cookie *cookie); -void fz_blend_pixmap(fz_pixmap *dst, fz_pixmap *src, int alpha, int blendmode, int isolated, fz_pixmap *shape); -void fz_blend_pixel(unsigned char dp[3], unsigned char bp[3], unsigned char sp[3], int blendmode); +/* + fz_free_display_list: Frees a display list. -enum -{ - /* PDF 1.4 -- standard separable */ - FZ_BLEND_NORMAL, - FZ_BLEND_MULTIPLY, - FZ_BLEND_SCREEN, - FZ_BLEND_OVERLAY, - FZ_BLEND_DARKEN, - FZ_BLEND_LIGHTEN, - FZ_BLEND_COLOR_DODGE, - FZ_BLEND_COLOR_BURN, - FZ_BLEND_HARD_LIGHT, - FZ_BLEND_SOFT_LIGHT, - FZ_BLEND_DIFFERENCE, - FZ_BLEND_EXCLUSION, - - /* PDF 1.4 -- standard non-separable */ - FZ_BLEND_HUE, - FZ_BLEND_SATURATION, - FZ_BLEND_COLOR, - FZ_BLEND_LUMINOSITY, - - /* For packing purposes */ - FZ_BLEND_MODEMASK = 15, - FZ_BLEND_ISOLATED = 16, - FZ_BLEND_KNOCKOUT = 32 -}; + list: Display list to be freed. Any objects put into the + display list by a list device will also be freed. + + Does not throw exceptions. +*/ +void fz_free_display_list(fz_context *ctx, fz_display_list *list); /* Links */ @@ -1590,6 +1727,35 @@ enum { fz_link_flag_r_is_zoom = 64 /* rb.x is actually a zoom figure */ }; +/* + fz_link_dest: XXX + + kind: Set to one of FZ_LINK_* to tell what what type of link + destination this is, and where in the union to look for + information. XXX + + gotor.page: Page number, 0 is the first page of the document. XXX + + gotor.flags: A bitfield consisting of fz_link_flag_* telling + what parts of gotor.lt and gotor.rb are valid, whether + fitting to width/height should be used, or if an arbitrary + zoom factor is used. XXX + + gotor.lt: The top left corner of the destination bounding box. XXX + gotor.rb: The bottom right corner of the destination bounding box. XXX + + gotor.file_spec: XXX + + gotor.new_window: XXX + + uri.uri: XXX + uri.is_map: XXX + + launch.file_spec: XXX + launch.new_window: XXX + + named.named: XXX +*/ struct fz_link_dest_s { fz_link_kind kind; @@ -1626,6 +1792,25 @@ struct fz_link_dest_s ld; }; +/* + fz_link is a list of interactive links on a page. + + There is no relation between the order of the links in the + list and the order they appear on the page. The list of links + for a given page can be obtained from fz_load_links. + + A link is reference counted. Dropping a reference to a link is + done by calling fz_drop_link. + + rect: The hot zone. The area that can be clicked in + untransformed coordinates. + + dest: Link destinations come in two forms: Page and area that + an application should display when this link is activated. Or + as an URI that can be given to a browser. + + next: A pointer to the next link on the same page. +*/ struct fz_link_s { int refs; @@ -1636,13 +1821,37 @@ struct fz_link_s fz_link *fz_new_link(fz_context *ctx, fz_rect bbox, fz_link_dest dest); fz_link *fz_keep_link(fz_context *ctx, fz_link *link); + +/* + fz_drop_link: Drop and free a list of links. + + Does not throw exceptions. +*/ void fz_drop_link(fz_context *ctx, fz_link *link); + void fz_free_link_dest(fz_context *ctx, fz_link_dest *dest); /* Outline */ typedef struct fz_outline_s fz_outline; +/* + fz_outline is a tree of the outline of a document (also known + as table of contents). + + title: Title of outline item using UTF-8 encoding. May be NULL + if the outline item has no text string. + + dest: Destination in the document to be displayed when this + outline item is activated. May be FZ_LINK_NONE if the outline + item does not have a destination. + + next: The next outline item at the same level as this outline + item. May be NULL if no more outline items exist at this level. + + down: The outline items immediate children in the hierarchy. + May be NULL if no children exist. +*/ struct fz_outline_s { char *title; @@ -1651,43 +1860,155 @@ struct fz_outline_s fz_outline *down; }; -void fz_debug_outline_xml(fz_context *ctx, fz_outline *outline, int level); -void fz_debug_outline(fz_context *ctx, fz_outline *outline, int level); -void fz_free_outline(fz_context *ctx, fz_outline *outline); +/* + fz_print_outline_xml: Dump the given outlines as (pseudo) XML. + + out: The file handle to output to. -/* Document interface */ + outline: The outlines to output. +*/ +void fz_print_outline_xml(fz_context *ctx, FILE *out, fz_outline *outline); +/* + fz_print_outline: Dump the given outlines to as text. + + out: The file handle to output to. + + outline: The outlines to output. +*/ +void fz_print_outline(fz_context *ctx, FILE *out, fz_outline *outline); + +/* + fz_free_outline: Free hierarchical outline. + + Free an outline obtained from fz_load_outline. + + Does not throw exceptions. +*/ +void fz_free_outline(fz_context *ctx, fz_outline *outline); + +/* + Document interface +*/ typedef struct fz_document_s fz_document; -typedef struct fz_page_s fz_page; /* doesn't have a definition -- always cast to *_page */ +typedef struct fz_page_s fz_page; -struct fz_document_s -{ - void (*close)(fz_document *); - int (*needs_password)(fz_document *doc); - int (*authenticate_password)(fz_document *doc, char *password); - fz_outline *(*load_outline)(fz_document *doc); - int (*count_pages)(fz_document *doc); - fz_page *(*load_page)(fz_document *doc, int number); - fz_link *(*load_links)(fz_document *doc, fz_page *page); - fz_rect (*bound_page)(fz_document *doc, fz_page *page); - void (*run_page)(fz_document *doc, fz_page *page, fz_device *dev, fz_matrix transform, fz_cookie *cookie); - void (*free_page)(fz_document *doc, fz_page *page); -}; +/* + fz_open_document: Open a PDF, XPS or CBZ document. + + Open a document file and read its basic structure so pages and + objects can be located. MuPDF will try to repair broken + documents (without actually changing the file contents). + The returned fz_document is used when calling most other + document related functions. Note that it wraps the context, so + those functions implicitly can access the global state in + context. + + filename: a path to a file as it would be given to open(2). +*/ fz_document *fz_open_document(fz_context *ctx, char *filename); +/* + fz_close_document: Close and free an open document. + + The resource store in the context associated with fz_document + is emptied, and any allocations for the document are freed. + + Does not throw exceptions. +*/ void fz_close_document(fz_document *doc); +/* + fz_needs_password: Check if a document is encrypted with a + non-blank password. + + Does not throw exceptions. +*/ int fz_needs_password(fz_document *doc); + +/* + fz_authenticate_password: Test if the given password can + decrypt the document. + + password: The password string to be checked. Some document + specifications do not specify any particular text encoding, so + neither do we. + + Does not throw exceptions. +*/ int fz_authenticate_password(fz_document *doc, char *password); +/* + fz_load_outline: Load the hierarchical document outline. + + Should be freed by fz_free_outline. +*/ fz_outline *fz_load_outline(fz_document *doc); +/* + fz_count_pages: Return the number of pages in document + + May return 0 for documents with no pages. +*/ int fz_count_pages(fz_document *doc); + +/* + fz_load_page: Load a page. + + After fz_load_page is it possible to retrieve the size of the + page using fz_bound_page, or to render the page using + fz_run_page_*. Free the page by calling fz_free_page. + + number: page number, 0 is the first page of the document. +*/ fz_page *fz_load_page(fz_document *doc, int number); + +/* + fz_load_links: Load the list of links for a page. + + Returns a linked list of all the links on the page, each with + its clickable region and link destination. Each link is + reference counted so drop and free the list of links by + calling fz_drop_link on the pointer return from fz_load_links. + + page: Page obtained from fz_load_page. +*/ fz_link *fz_load_links(fz_document *doc, fz_page *page); + +/* + fz_bound_page: Determine the size of a page at 72 dpi. + + Does not throw exceptions. +*/ fz_rect fz_bound_page(fz_document *doc, fz_page *page); + +/* + fz_run_page: Run a page through a device. + + page: Page obtained from fz_load_page. + + dev: Device obtained from fz_new_*_device. + + transform: Transform to apply to page. May include for example + scaling and rotation, see fz_scale, fz_rotate and fz_concat. + Set to fz_identity if no transformation is desired. + + cookie: Communication mechanism between caller and library + rendering the page. Intended for multi-threaded applications, + while single-threaded applications set cookie to NULL. The + caller may abort an ongoing rendering of a page. Cookie also + communicates progress information back to the caller. The + fields inside cookie are continually updated while the page is + rendering. +*/ void fz_run_page(fz_document *doc, fz_page *page, fz_device *dev, fz_matrix transform, fz_cookie *cookie); + +/* + fz_free_page: Free a loaded page. + + Does not throw exceptions. +*/ void fz_free_page(fz_document *doc, fz_page *page); #endif diff --git a/fitz/image_jpeg.c b/fitz/image_jpeg.c index f53b6124..2840adbf 100644 --- a/fitz/image_jpeg.c +++ b/fitz/image_jpeg.c @@ -1,4 +1,4 @@ -#include "fitz.h" +#include "fitz-internal.h" #include <jpeglib.h> #include <setjmp.h> @@ -115,6 +115,9 @@ fz_load_jpeg(fz_context *ctx, unsigned char *rbuf, int rlen) image->yres = cinfo.Y_density * 254 / 100; } + if (image->xres <= 0) image->xres = 72; + if (image->yres <= 0) image->yres = 72; + fz_clear_pixmap(ctx, image); row[0] = fz_malloc(ctx, cinfo.output_components * cinfo.output_width); diff --git a/fitz/image_jpx.c b/fitz/image_jpx.c index 4d76b4e8..ac1db35a 100644 --- a/fitz/image_jpx.c +++ b/fitz/image_jpx.c @@ -1,4 +1,4 @@ -#include "fitz.h" +#include "fitz-internal.h" #define OPJ_STATIC #include <openjpeg.h> @@ -144,7 +144,7 @@ fz_load_jpx(fz_context *ctx, unsigned char *data, int size, fz_colorspace *defcs if (n == 4) { fz_pixmap *tmp = fz_new_pixmap(ctx, fz_device_rgb, w, h); - fz_convert_pixmap(ctx, img, tmp); + fz_convert_pixmap(ctx, tmp, img); fz_drop_pixmap(ctx, img); img = tmp; } diff --git a/fitz/image_md5.c b/fitz/image_md5.c new file mode 100644 index 00000000..86ba0a12 --- /dev/null +++ b/fitz/image_md5.c @@ -0,0 +1,11 @@ +#include "fitz-internal.h" + +void fz_md5_pixmap(fz_pixmap *pix, unsigned char digest[16]) +{ + fz_md5 md5; + + fz_md5_init(&md5); + if (pix) + fz_md5_update(&md5, pix->samples, pix->w * pix->h * pix->n); + fz_md5_final(&md5, digest); +} diff --git a/fitz/image_png.c b/fitz/image_png.c index b3fe39cc..e2092c10 100644 --- a/fitz/image_png.c +++ b/fitz/image_png.c @@ -1,4 +1,4 @@ -#include "fitz.h" +#include "fitz-internal.h" #include <zlib.h> diff --git a/fitz/image_save.c b/fitz/image_save.c new file mode 100644 index 00000000..95be1cd3 --- /dev/null +++ b/fitz/image_save.c @@ -0,0 +1,32 @@ +#include "fitz-internal.h" + +void fz_write_pixmap(fz_context *ctx, fz_pixmap *img, char *file, int rgb) +{ + char name[1024]; + fz_pixmap *converted = NULL; + + if (!img) + return; + + if (rgb && img->colorspace && img->colorspace != fz_device_rgb) + { + converted = fz_new_pixmap_with_bbox(ctx, fz_device_rgb, fz_pixmap_bbox(ctx, img)); + fz_convert_pixmap(ctx, converted, img); + img = converted; + } + + if (img->n <= 4) + { + sprintf(name, "%s.png", file); + printf("extracting image %s\n", name); + fz_write_png(ctx, img, name, 0); + } + else + { + sprintf(name, "%s.pam", file); + printf("extracting image %s\n", name); + fz_write_pam(ctx, img, name, 0); + } + + fz_drop_pixmap(ctx, converted); +} diff --git a/fitz/image_tiff.c b/fitz/image_tiff.c index fff91a9e..ffd0ea88 100644 --- a/fitz/image_tiff.c +++ b/fitz/image_tiff.c @@ -1,4 +1,4 @@ -#include "fitz.h" +#include "fitz-internal.h" /* * TIFF image loader. Should be enough to support TIFF files in XPS. @@ -789,7 +789,7 @@ fz_load_tiff(fz_context *ctx, unsigned char *buf, int len) if (image->n == 5) { fz_pixmap *rgb = fz_new_pixmap(tiff.ctx, fz_device_rgb, image->w, image->h); - fz_convert_pixmap(tiff.ctx, image, rgb); + fz_convert_pixmap(tiff.ctx, rgb, image); rgb->xres = image->xres; rgb->yres = image->yres; fz_drop_pixmap(ctx, image); diff --git a/fitz/res_bitmap.c b/fitz/res_bitmap.c index 2aa28b02..1bd2827d 100644 --- a/fitz/res_bitmap.c +++ b/fitz/res_bitmap.c @@ -1,4 +1,4 @@ -#include "fitz.h" +#include "fitz-internal.h" fz_bitmap * fz_new_bitmap(fz_context *ctx, int w, int h, int n) @@ -74,3 +74,48 @@ fz_write_pbm(fz_context *ctx, fz_bitmap *bitmap, char *filename) fclose(fp); } + +fz_colorspace *fz_pixmap_colorspace(fz_context *ctx, fz_pixmap *pix) +{ + if (!pix) + return NULL; + return pix->colorspace; +} + +int fz_pixmap_components(fz_context *ctx, fz_pixmap *pix) +{ + if (!pix) + return 0; + return pix->n; +} + +unsigned char *fz_pixmap_samples(fz_context *ctx, fz_pixmap *pix) +{ + if (!pix) + return NULL; + return pix->samples; +} + +void fz_bitmap_details(fz_bitmap *bit, int *w, int *h, int *n, int *stride) +{ + if (!bit) + { + if (w) + *w = 0; + if (h) + *h = 0; + if (n) + *n = 0; + if (stride) + *stride = 0; + return; + } + if (w) + *w = bit->w; + if (h) + *h = bit->h; + if (n) + *n = bit->n; + if (stride) + *w = bit->stride; +} diff --git a/fitz/res_colorspace.c b/fitz/res_colorspace.c index 413da3ae..587db381 100644 --- a/fitz/res_colorspace.c +++ b/fitz/res_colorspace.c @@ -1,4 +1,4 @@ -#include "fitz.h" +#include "fitz-internal.h" #define SLOWCMYK @@ -164,7 +164,7 @@ fz_colorspace *fz_device_bgr = &k_device_bgr; fz_colorspace *fz_device_cmyk = &k_device_cmyk; fz_colorspace * -fz_find_device_colorspace(char *name) +fz_find_device_colorspace(fz_context *ctx, char *name) { if (!strcmp(name, "DeviceGray")) return fz_device_gray; @@ -180,7 +180,7 @@ fz_find_device_colorspace(char *name) /* Fast pixmap color conversions */ -static void fast_gray_to_rgb(fz_pixmap *src, fz_pixmap *dst) +static void fast_gray_to_rgb(fz_pixmap *dst, fz_pixmap *src) { unsigned char *s = src->samples; unsigned char *d = dst->samples; @@ -196,7 +196,7 @@ static void fast_gray_to_rgb(fz_pixmap *src, fz_pixmap *dst) } } -static void fast_gray_to_cmyk(fz_pixmap *src, fz_pixmap *dst) +static void fast_gray_to_cmyk(fz_pixmap *dst, fz_pixmap *src) { unsigned char *s = src->samples; unsigned char *d = dst->samples; @@ -213,7 +213,7 @@ static void fast_gray_to_cmyk(fz_pixmap *src, fz_pixmap *dst) } } -static void fast_rgb_to_gray(fz_pixmap *src, fz_pixmap *dst) +static void fast_rgb_to_gray(fz_pixmap *dst, fz_pixmap *src) { unsigned char *s = src->samples; unsigned char *d = dst->samples; @@ -227,7 +227,7 @@ static void fast_rgb_to_gray(fz_pixmap *src, fz_pixmap *dst) } } -static void fast_bgr_to_gray(fz_pixmap *src, fz_pixmap *dst) +static void fast_bgr_to_gray(fz_pixmap *dst, fz_pixmap *src) { unsigned char *s = src->samples; unsigned char *d = dst->samples; @@ -241,7 +241,7 @@ static void fast_bgr_to_gray(fz_pixmap *src, fz_pixmap *dst) } } -static void fast_rgb_to_cmyk(fz_pixmap *src, fz_pixmap *dst) +static void fast_rgb_to_cmyk(fz_pixmap *dst, fz_pixmap *src) { unsigned char *s = src->samples; unsigned char *d = dst->samples; @@ -262,7 +262,7 @@ static void fast_rgb_to_cmyk(fz_pixmap *src, fz_pixmap *dst) } } -static void fast_bgr_to_cmyk(fz_pixmap *src, fz_pixmap *dst) +static void fast_bgr_to_cmyk(fz_pixmap *dst, fz_pixmap *src) { unsigned char *s = src->samples; unsigned char *d = dst->samples; @@ -283,7 +283,7 @@ static void fast_bgr_to_cmyk(fz_pixmap *src, fz_pixmap *dst) } } -static void fast_cmyk_to_gray(fz_pixmap *src, fz_pixmap *dst) +static void fast_cmyk_to_gray(fz_pixmap *dst, fz_pixmap *src) { unsigned char *s = src->samples; unsigned char *d = dst->samples; @@ -300,7 +300,7 @@ static void fast_cmyk_to_gray(fz_pixmap *src, fz_pixmap *dst) } } -static void fast_cmyk_to_rgb(fz_context *ctx, fz_pixmap *src, fz_pixmap *dst) +static void fast_cmyk_to_rgb(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src) { unsigned char *s = src->samples; unsigned char *d = dst->samples; @@ -328,7 +328,7 @@ static void fast_cmyk_to_rgb(fz_context *ctx, fz_pixmap *src, fz_pixmap *dst) } } -static void fast_cmyk_to_bgr(fz_context *ctx, fz_pixmap *src, fz_pixmap *dst) +static void fast_cmyk_to_bgr(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src) { unsigned char *s = src->samples; unsigned char *d = dst->samples; @@ -356,7 +356,7 @@ static void fast_cmyk_to_bgr(fz_context *ctx, fz_pixmap *src, fz_pixmap *dst) } } -static void fast_rgb_to_bgr(fz_pixmap *src, fz_pixmap *dst) +static void fast_rgb_to_bgr(fz_pixmap *dst, fz_pixmap *src) { unsigned char *s = src->samples; unsigned char *d = dst->samples; @@ -373,7 +373,7 @@ static void fast_rgb_to_bgr(fz_pixmap *src, fz_pixmap *dst) } static void -fz_std_conv_pixmap(fz_context *ctx, fz_pixmap *src, fz_pixmap *dst) +fz_std_conv_pixmap(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src) { float srcv[FZ_MAX_COLORS]; float dstv[FZ_MAX_COLORS]; @@ -404,7 +404,7 @@ fz_std_conv_pixmap(fz_context *ctx, fz_pixmap *src, fz_pixmap *dst) srcv[1] = *s++ - 128; srcv[2] = *s++ - 128; - fz_convert_color(ctx, ss, srcv, ds, dstv); + fz_convert_color(ctx, ds, dstv, ss, srcv); for (k = 0; k < dstn; k++) *d++ = dstv[k] * 255; @@ -424,7 +424,7 @@ fz_std_conv_pixmap(fz_context *ctx, fz_pixmap *src, fz_pixmap *dst) for (k = 0; k < srcn; k++) srcv[k] = *s++ / 255.0f; - fz_convert_color(ctx, ss, srcv, ds, dstv); + fz_convert_color(ctx, ds, dstv, ss, srcv); for (k = 0; k < dstn; k++) *d++ = dstv[k] * 255; @@ -442,7 +442,7 @@ fz_std_conv_pixmap(fz_context *ctx, fz_pixmap *src, fz_pixmap *dst) for (i = 0; i < 256; i++) { srcv[0] = i / 255.0f; - fz_convert_color(ctx, ss, srcv, ds, dstv); + fz_convert_color(ctx, ds, dstv, ss, srcv); for (k = 0; k < dstn; k++) lookup[i * dstn + k] = dstv[k] * 255; } @@ -465,7 +465,7 @@ fz_std_conv_pixmap(fz_context *ctx, fz_pixmap *src, fz_pixmap *dst) fz_hash_table *lookup; unsigned char *color; - lookup = fz_new_hash_table(ctx, 509, srcn); + lookup = fz_new_hash_table(ctx, 509, srcn, -1); for (y = 0; y < src->h; y++) { @@ -483,7 +483,7 @@ fz_std_conv_pixmap(fz_context *ctx, fz_pixmap *src, fz_pixmap *dst) { for (k = 0; k < srcn; k++) srcv[k] = *s++ / 255.0f; - fz_convert_color(ctx, ss, srcv, ds, dstv); + fz_convert_color(ctx, ds, dstv, ss, srcv); for (k = 0; k < dstn; k++) *d++ = dstv[k] * 255; @@ -499,50 +499,48 @@ fz_std_conv_pixmap(fz_context *ctx, fz_pixmap *src, fz_pixmap *dst) } void -fz_convert_pixmap(fz_context *ctx, fz_pixmap *sp, fz_pixmap *dp) +fz_convert_pixmap(fz_context *ctx, fz_pixmap *dp, fz_pixmap *sp) { fz_colorspace *ss = sp->colorspace; fz_colorspace *ds = dp->colorspace; assert(ss && ds); - if (sp->mask) - dp->mask = fz_keep_pixmap(ctx, sp->mask); dp->interpolate = sp->interpolate; if (ss == fz_device_gray) { - if (ds == fz_device_rgb) fast_gray_to_rgb(sp, dp); - else if (ds == fz_device_bgr) fast_gray_to_rgb(sp, dp); /* bgr == rgb here */ - else if (ds == fz_device_cmyk) fast_gray_to_cmyk(sp, dp); - else fz_std_conv_pixmap(ctx, sp, dp); + if (ds == fz_device_rgb) fast_gray_to_rgb(dp, sp); + else if (ds == fz_device_bgr) fast_gray_to_rgb(dp, sp); /* bgr == rgb here */ + else if (ds == fz_device_cmyk) fast_gray_to_cmyk(dp, sp); + else fz_std_conv_pixmap(ctx, dp, sp); } else if (ss == fz_device_rgb) { - if (ds == fz_device_gray) fast_rgb_to_gray(sp, dp); - else if (ds == fz_device_bgr) fast_rgb_to_bgr(sp, dp); - else if (ds == fz_device_cmyk) fast_rgb_to_cmyk(sp, dp); - else fz_std_conv_pixmap(ctx, sp, dp); + if (ds == fz_device_gray) fast_rgb_to_gray(dp, sp); + else if (ds == fz_device_bgr) fast_rgb_to_bgr(dp, sp); + else if (ds == fz_device_cmyk) fast_rgb_to_cmyk(dp, sp); + else fz_std_conv_pixmap(ctx, dp, sp); } else if (ss == fz_device_bgr) { - if (ds == fz_device_gray) fast_bgr_to_gray(sp, dp); - else if (ds == fz_device_rgb) fast_rgb_to_bgr(sp, dp); /* bgr = rgb here */ + if (ds == fz_device_gray) fast_bgr_to_gray(dp, sp); + else if (ds == fz_device_rgb) fast_rgb_to_bgr(dp, sp); /* bgr = rgb here */ else if (ds == fz_device_cmyk) fast_bgr_to_cmyk(sp, dp); - else fz_std_conv_pixmap(ctx, sp, dp); + else fz_std_conv_pixmap(ctx, dp, sp); } else if (ss == fz_device_cmyk) { - if (ds == fz_device_gray) fast_cmyk_to_gray(sp, dp); - else if (ds == fz_device_bgr) fast_cmyk_to_bgr(ctx, sp, dp); - else if (ds == fz_device_rgb) fast_cmyk_to_rgb(ctx, sp, dp); - else fz_std_conv_pixmap(ctx, sp, dp); + if (ds == fz_device_gray) fast_cmyk_to_gray(dp, sp); + else if (ds == fz_device_bgr) fast_cmyk_to_bgr(ctx, dp, sp); + else if (ds == fz_device_rgb) fast_cmyk_to_rgb(ctx, dp, sp); + else fz_std_conv_pixmap(ctx, dp, sp); } - else fz_std_conv_pixmap(ctx, sp, dp); + else fz_std_conv_pixmap(ctx, dp, sp); } /* Convert a single color */ @@ -569,7 +567,7 @@ fz_std_conv_color(fz_context *ctx, fz_colorspace *srcs, float *srcv, fz_colorspa } void -fz_convert_color(fz_context *ctx, fz_colorspace *ss, float *sv, fz_colorspace *ds, float *dv) +fz_convert_color(fz_context *ctx, fz_colorspace *ds, float *dv, fz_colorspace *ss, float *sv) { if (ss == fz_device_gray) { diff --git a/fitz/res_font.c b/fitz/res_font.c index 7a194da6..c1db35d8 100644 --- a/fitz/res_font.c +++ b/fitz/res_font.c @@ -1,4 +1,4 @@ -#include "fitz.h" +#include "fitz-internal.h" #include <ft2build.h> #include FT_FREETYPE_H @@ -93,7 +93,7 @@ fz_drop_font(fz_context *ctx, fz_font *font) if (font->t3procs) { if (font->t3resources) - fz_drop_obj(font->t3resources); + font->t3freeres(font->t3doc, font->t3resources); for (i = 0; i < 256; i++) if (font->t3procs[i]) fz_drop_buffer(ctx, font->t3procs[i]); @@ -387,12 +387,13 @@ fz_copy_ft_bitmap(fz_context *ctx, int left, int top, FT_Bitmap *bitmap) /* The glyph cache lock is always taken when this is called. */ fz_pixmap * -fz_render_ft_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm) +fz_render_ft_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm, int aa) { FT_Face face = font->ft_face; FT_Matrix m; FT_Vector v; FT_Error fterr; + fz_pixmap *result; trm = fz_adjust_ft_glyph_width(ctx, font, gid, trm); @@ -420,7 +421,7 @@ fz_render_ft_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm) fz_warn(ctx, "freetype setting character size: %s", ft_error_string(fterr)); FT_Set_Transform(face, &m, &v); - if (fz_get_aa_level(ctx) == 0) + if (aa == 0) { /* If you really want grid fitting, enable this code. */ float scale = fz_matrix_expansion(trm); @@ -470,16 +471,17 @@ fz_render_ft_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm) FT_Outline_Translate(&face->glyph->outline, -strength * 32, -strength * 32); } - fterr = FT_Render_Glyph(face->glyph, fz_get_aa_level(ctx) > 0 ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO); + fterr = FT_Render_Glyph(face->glyph, fz_aa_level(ctx) > 0 ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO); if (fterr) { fz_warn(ctx, "freetype render glyph (gid %d): %s", gid, ft_error_string(fterr)); fz_unlock(ctx, FZ_LOCK_FREETYPE); return NULL; } - fz_unlock(ctx, FZ_LOCK_FREETYPE); - return fz_copy_ft_bitmap(ctx, face->glyph->bitmap_left, face->glyph->bitmap_top, &face->glyph->bitmap); + result = fz_copy_ft_bitmap(ctx, face->glyph->bitmap_left, face->glyph->bitmap_top, &face->glyph->bitmap); + fz_unlock(ctx, FZ_LOCK_FREETYPE); + return result; } fz_pixmap * @@ -573,7 +575,7 @@ fz_render_ft_stroked_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix tr FT_Stroker_Done(stroker); - fterr = FT_Glyph_To_Bitmap(&glyph, fz_get_aa_level(ctx) > 0 ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO, 0, 1); + fterr = FT_Glyph_To_Bitmap(&glyph, fz_aa_level(ctx) > 0 ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO, 0, 1); if (fterr) { fz_warn(ctx, "FT_Glyph_To_Bitmap: %s", ft_error_string(fterr)); @@ -754,7 +756,7 @@ fz_render_t3_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm, fz_co bbox.x1++; bbox.y1++; - glyph = fz_new_pixmap_with_rect(ctx, model ? model : fz_device_gray, bbox); + glyph = fz_new_pixmap_with_bbox(ctx, model ? model : fz_device_gray, bbox); fz_clear_pixmap(ctx, glyph); ctm = fz_concat(font->t3matrix, trm); @@ -806,29 +808,29 @@ fz_render_t3_glyph_direct(fz_context *ctx, fz_device *dev, fz_font *font, int gi } void -fz_debug_font(fz_context *ctx, fz_font *font) +fz_print_font(fz_context *ctx, FILE *out, fz_font *font) { - printf("font '%s' {\n", font->name); + fprintf(out, "font '%s' {\n", font->name); if (font->ft_face) { - printf("\tfreetype face %p\n", font->ft_face); + fprintf(out, "\tfreetype face %p\n", font->ft_face); if (font->ft_substitute) - printf("\tsubstitute font\n"); + fprintf(out, "\tsubstitute font\n"); } if (font->t3procs) { - printf("\ttype3 matrix [%g %g %g %g]\n", + fprintf(out, "\ttype3 matrix [%g %g %g %g]\n", font->t3matrix.a, font->t3matrix.b, font->t3matrix.c, font->t3matrix.d); - printf("\ttype3 bbox [%g %g %g %g]\n", + fprintf(out, "\ttype3 bbox [%g %g %g %g]\n", font->bbox.x0, font->bbox.y0, font->bbox.x1, font->bbox.y1); } - printf("}\n"); + fprintf(out, "}\n"); } fz_rect diff --git a/fitz/res_halftone.c b/fitz/res_halftone.c index 7258ad01..daad6e37 100644 --- a/fitz/res_halftone.c +++ b/fitz/res_halftone.c @@ -1,4 +1,4 @@ -#include "fitz.h" +#include "fitz-internal.h" fz_halftone * fz_new_halftone(fz_context *ctx, int comps) @@ -56,7 +56,7 @@ static unsigned char mono_ht[] = 0xF2, 0x72, 0xD2, 0x52, 0xFA, 0x7A, 0xDA, 0x5A, 0xF0, 0x70, 0xD0, 0x50, 0xF8, 0x78, 0xD8, 0x58 }; -fz_halftone *fz_get_default_halftone(fz_context *ctx, int num_comps) +fz_halftone *fz_default_halftone(fz_context *ctx, int num_comps) { fz_halftone *ht = fz_new_halftone(ctx, num_comps); assert(num_comps == 1); /* Only support 1 component for now */ @@ -162,13 +162,18 @@ fz_bitmap *fz_halftone_pixmap(fz_context *ctx, fz_pixmap *pix, fz_halftone *ht) fz_bitmap *out; unsigned char *ht_line, *o, *p; int w, h, x, y, n, pstride, ostride; + fz_halftone *ht_orig = ht; - if (!pix || !ht) + if (!pix) return NULL; assert(pix->n == 2); /* Mono + Alpha */ n = pix->n-1; /* Remove alpha */ + if (ht == NULL) + { + ht = fz_default_halftone(ctx, n); + } ht_line = fz_malloc(ctx, pix->w * n); out = fz_new_bitmap(ctx, pix->w, pix->h, n); o = out->samples; @@ -187,5 +192,7 @@ fz_bitmap *fz_halftone_pixmap(fz_context *ctx, fz_pixmap *pix, fz_halftone *ht) o += ostride; p += pstride; } + if (!ht_orig) + fz_drop_halftone(ctx, ht); return out; } diff --git a/fitz/res_path.c b/fitz/res_path.c index a645f9d5..45ead677 100644 --- a/fitz/res_path.c +++ b/fitz/res_path.c @@ -1,5 +1,5 @@ #include <assert.h> -#include "fitz.h" +#include "fitz-internal.h" fz_path * fz_new_path(fz_context *ctx) @@ -316,7 +316,7 @@ fz_transform_path(fz_context *ctx, fz_path *path, fz_matrix ctm) } void -fz_debug_path(fz_context *ctx, fz_path *path, int indent) +fz_print_path(fz_context *ctx, FILE *out, fz_path *path, int indent) { float x, y; int i = 0; @@ -324,32 +324,32 @@ fz_debug_path(fz_context *ctx, fz_path *path, int indent) while (i < path->len) { for (n = 0; n < indent; n++) - putchar(' '); + fputc(' ', out); switch (path->items[i++].k) { case FZ_MOVETO: x = path->items[i++].v; y = path->items[i++].v; - printf("%g %g m\n", x, y); + fprintf(out, "%g %g m\n", x, y); break; case FZ_LINETO: x = path->items[i++].v; y = path->items[i++].v; - printf("%g %g l\n", x, y); + fprintf(out, "%g %g l\n", x, y); break; case FZ_CURVETO: x = path->items[i++].v; y = path->items[i++].v; - printf("%g %g ", x, y); + fprintf(out, "%g %g ", x, y); x = path->items[i++].v; y = path->items[i++].v; - printf("%g %g ", x, y); + fprintf(out, "%g %g ", x, y); x = path->items[i++].v; y = path->items[i++].v; - printf("%g %g c\n", x, y); + fprintf(out, "%g %g c\n", x, y); break; case FZ_CLOSE_PATH: - printf("h\n"); + fprintf(out, "h\n"); break; } } diff --git a/fitz/res_pixmap.c b/fitz/res_pixmap.c index dbed0842..a160b6ca 100644 --- a/fitz/res_pixmap.c +++ b/fitz/res_pixmap.c @@ -1,4 +1,4 @@ -#include "fitz.h" +#include "fitz-internal.h" fz_pixmap * fz_keep_pixmap(fz_context *ctx, fz_pixmap *pix) @@ -17,8 +17,6 @@ fz_free_pixmap_imp(fz_context *ctx, fz_storable *pix_) { fz_pixmap *pix = (fz_pixmap *)pix_; - if (pix->mask) - fz_drop_pixmap(ctx, pix->mask); if (pix->colorspace) fz_drop_colorspace(ctx, pix->colorspace); if (pix->free_samples) @@ -37,7 +35,6 @@ fz_new_pixmap_with_data(fz_context *ctx, fz_colorspace *colorspace, int w, int h pix->y = 0; pix->w = w; pix->h = h; - pix->mask = NULL; pix->interpolate = 1; pix->xres = 96; pix->yres = 96; @@ -65,6 +62,8 @@ fz_new_pixmap_with_data(fz_context *ctx, fz_colorspace *colorspace, int w, int h } fz_catch(ctx) { + if (colorspace) + fz_drop_colorspace(ctx, colorspace); fz_free(ctx, pix); fz_rethrow(ctx); } @@ -81,7 +80,7 @@ fz_new_pixmap(fz_context *ctx, fz_colorspace *colorspace, int w, int h) } fz_pixmap * -fz_new_pixmap_with_rect(fz_context *ctx, fz_colorspace *colorspace, fz_bbox r) +fz_new_pixmap_with_bbox(fz_context *ctx, fz_colorspace *colorspace, fz_bbox r) { fz_pixmap *pixmap; pixmap = fz_new_pixmap(ctx, colorspace, r.x1 - r.x0, r.y1 - r.y0); @@ -91,7 +90,7 @@ fz_new_pixmap_with_rect(fz_context *ctx, fz_colorspace *colorspace, fz_bbox r) } fz_pixmap * -fz_new_pixmap_with_rect_and_data(fz_context *ctx, fz_colorspace *colorspace, fz_bbox r, unsigned char *samples) +fz_new_pixmap_with_bbox_and_data(fz_context *ctx, fz_colorspace *colorspace, fz_bbox r, unsigned char *samples) { fz_pixmap *pixmap; pixmap = fz_new_pixmap_with_data(ctx, colorspace, r.x1 - r.x0, r.y1 - r.y0, samples); @@ -101,7 +100,7 @@ fz_new_pixmap_with_rect_and_data(fz_context *ctx, fz_colorspace *colorspace, fz_ } fz_bbox -fz_bound_pixmap(fz_pixmap *pix) +fz_pixmap_bbox(fz_context *ctx, fz_pixmap *pix) { fz_bbox bbox; bbox.x0 = pix->x; @@ -111,6 +110,29 @@ fz_bound_pixmap(fz_pixmap *pix) return bbox; } +fz_bbox +fz_pixmap_bbox_no_ctx(fz_pixmap *pix) +{ + fz_bbox bbox; + bbox.x0 = pix->x; + bbox.y0 = pix->y; + bbox.x1 = pix->x + pix->w; + bbox.y1 = pix->y + pix->h; + return bbox; +} + +int +fz_pixmap_width(fz_context *ctx, fz_pixmap *pix) +{ + return pix->w; +} + +int +fz_pixmap_height(fz_context *ctx, fz_pixmap *pix) +{ + return pix->h; +} + void fz_clear_pixmap(fz_context *ctx, fz_pixmap *pix) { @@ -145,8 +167,8 @@ fz_copy_pixmap_rect(fz_context *ctx, fz_pixmap *dest, fz_pixmap *src, fz_bbox r) unsigned char *destp; int y, w, destspan, srcspan; - r = fz_intersect_bbox(r, fz_bound_pixmap(dest)); - r = fz_intersect_bbox(r, fz_bound_pixmap(src)); + r = fz_intersect_bbox(r, fz_pixmap_bbox(ctx, dest)); + r = fz_intersect_bbox(r, fz_pixmap_bbox(ctx, src)); w = r.x1 - r.x0; y = r.y1 - r.y0; if (w <= 0 || y <= 0) @@ -172,7 +194,7 @@ fz_clear_pixmap_rect_with_value(fz_context *ctx, fz_pixmap *dest, int value, fz_ unsigned char *destp; int x, y, w, k, destspan; - r = fz_intersect_bbox(r, fz_bound_pixmap(dest)); + r = fz_intersect_bbox(r, fz_pixmap_bbox(ctx, dest)); w = r.x1 - r.x0; y = r.y1 - r.y0; if (w <= 0 || y <= 0) @@ -250,7 +272,7 @@ fz_alpha_from_gray(fz_context *ctx, fz_pixmap *gray, int luminosity) assert(gray->n == 2); - alpha = fz_new_pixmap_with_rect(ctx, NULL, fz_bound_pixmap(gray)); + alpha = fz_new_pixmap_with_bbox(ctx, NULL, fz_pixmap_bbox(ctx, gray)); dp = alpha->samples; sp = gray->samples; if (!luminosity) @@ -283,6 +305,27 @@ fz_invert_pixmap(fz_context *ctx, fz_pixmap *pix) } } +void fz_invert_pixmap_rect(fz_pixmap *image, fz_bbox rect) +{ + unsigned char *p; + int x, y, n; + + int x0 = CLAMP(rect.x0 - image->x, 0, image->w - 1); + int x1 = CLAMP(rect.x1 - image->x, 0, image->w - 1); + int y0 = CLAMP(rect.y0 - image->y, 0, image->h - 1); + int y1 = CLAMP(rect.y1 - image->y, 0, image->h - 1); + + for (y = y0; y < y1; y++) + { + p = image->samples + (y * image->w + x0) * image->n; + for (x = x0; x < x1; x++) + { + for (n = image->n; n > 0; n--, p++) + *p = 255 - *p; + } + } +} + void fz_gamma_pixmap(fz_context *ctx, fz_pixmap *pix, float gamma) { @@ -549,3 +592,23 @@ fz_pixmap_size(fz_context *ctx, fz_pixmap * pix) return 0; return sizeof(*pix) + pix->n * pix->w * pix->h; } + +fz_pixmap * +fz_image_to_pixmap(fz_context *ctx, fz_image *image, int w, int h) +{ + if (image == NULL) + return NULL; + return image->get_pixmap(ctx, image, w, h); +} + +fz_image * +fz_keep_image(fz_context *ctx, fz_image *image) +{ + return (fz_image *)fz_keep_storable(ctx, &image->storable); +} + +void +fz_drop_image(fz_context *ctx, fz_image *image) +{ + fz_drop_storable(ctx, &image->storable); +} diff --git a/fitz/res_shade.c b/fitz/res_shade.c index 3fdf2e15..d2b2f44b 100644 --- a/fitz/res_shade.c +++ b/fitz/res_shade.c @@ -1,4 +1,4 @@ -#include "fitz.h" +#include "fitz-internal.h" fz_shade * fz_keep_shade(fz_context *ctx, fz_shade *shade) @@ -68,59 +68,59 @@ fz_bound_shade(fz_context *ctx, fz_shade *shade, fz_matrix ctm) } void -fz_debug_shade(fz_context *ctx, fz_shade *shade) +fz_print_shade(fz_context *ctx, FILE *out, fz_shade *shade) { int i, j, n; float *vertex; int triangle; - printf("shading {\n"); + fprintf(out, "shading {\n"); switch (shade->type) { - case FZ_LINEAR: printf("\ttype linear\n"); break; - case FZ_RADIAL: printf("\ttype radial\n"); break; - case FZ_MESH: printf("\ttype mesh\n"); break; + case FZ_LINEAR: fprintf(out, "\ttype linear\n"); break; + case FZ_RADIAL: fprintf(out, "\ttype radial\n"); break; + case FZ_MESH: fprintf(out, "\ttype mesh\n"); break; } - printf("\tbbox [%g %g %g %g]\n", + fprintf(out, "\tbbox [%g %g %g %g]\n", shade->bbox.x0, shade->bbox.y0, shade->bbox.x1, shade->bbox.y1); - printf("\tcolorspace %s\n", shade->colorspace->name); + fprintf(out, "\tcolorspace %s\n", shade->colorspace->name); - printf("\tmatrix [%g %g %g %g %g %g]\n", + fprintf(out, "\tmatrix [%g %g %g %g %g %g]\n", shade->matrix.a, shade->matrix.b, shade->matrix.c, shade->matrix.d, shade->matrix.e, shade->matrix.f); if (shade->use_background) { - printf("\tbackground ["); + fprintf(out, "\tbackground ["); for (i = 0; i < shade->colorspace->n; i++) - printf("%s%g", i == 0 ? "" : " ", shade->background[i]); - printf("]\n"); + fprintf(out, "%s%g", i == 0 ? "" : " ", shade->background[i]); + fprintf(out, "]\n"); } if (shade->use_function) { - printf("\tfunction\n"); + fprintf(out, "\tfunction\n"); n = 3; } else n = 2 + shade->colorspace->n; - printf("\tvertices: %d\n", shade->mesh_len); + fprintf(out, "\tvertices: %d\n", shade->mesh_len); vertex = shade->mesh; triangle = 0; i = 0; while (i < shade->mesh_len) { - printf("\t%d:(%g, %g): ", triangle, vertex[0], vertex[1]); + fprintf(out, "\t%d:(%g, %g): ", triangle, vertex[0], vertex[1]); for (j = 2; j < n; j++) - printf("%s%g", j == 2 ? "" : " ", vertex[j]); - printf("\n"); + fprintf(out, "%s%g", j == 2 ? "" : " ", vertex[j]); + fprintf(out, "\n"); vertex += n; i++; @@ -128,5 +128,5 @@ fz_debug_shade(fz_context *ctx, fz_shade *shade) triangle++; } - printf("}\n"); + fprintf(out, "}\n"); } diff --git a/fitz/res_store.c b/fitz/res_store.c index 5eec1f0d..8e5375d6 100644 --- a/fitz/res_store.c +++ b/fitz/res_store.c @@ -1,21 +1,16 @@ -#include "fitz.h" -#include "mupdf.h" +#include "fitz-internal.h" + +typedef struct fz_item_s fz_item; struct fz_item_s { - fz_obj *key; + void *key; fz_storable *val; unsigned int size; fz_item *next; fz_item *prev; fz_store *store; -}; - -struct refkey -{ - fz_store_free_fn *free; - int num; - int gen; + fz_store_type *type; }; struct fz_store_s @@ -43,7 +38,7 @@ fz_new_store_context(fz_context *ctx, unsigned int max) store = fz_malloc_struct(ctx, fz_store); fz_try(ctx) { - store->hash = fz_new_hash_table(ctx, 4096, sizeof(struct refkey)); + store->hash = fz_new_hash_table(ctx, 4096, sizeof(fz_store_hash), FZ_LOCK_ALLOC); } fz_catch(ctx) { @@ -114,20 +109,19 @@ evict(fz_context *ctx, fz_item *item) store->head = item->next; /* Drop a reference to the value (freeing if required) */ drop = (item->val->refs > 0 && --item->val->refs == 0); - fz_unlock(ctx, FZ_LOCK_ALLOC); /* Remove from the hash table */ - if (fz_is_indirect(item->key)) + if (item->type->make_hash_key) { - struct refkey refkey; - refkey.free = item->val->free; - refkey.num = fz_to_num(item->key); - refkey.gen = fz_to_gen(item->key); - fz_hash_remove(ctx, store->hash, &refkey); + fz_store_hash hash = { NULL }; + hash.free = item->val->free; + if (item->type->make_hash_key(&hash, item->key)) + fz_hash_remove(ctx, store->hash, &hash); } + fz_unlock(ctx, FZ_LOCK_ALLOC); if (drop) item->val->free(ctx, item->val); /* Always drops the key and free the item */ - fz_drop_obj(item->key); + item->type->drop_key(ctx, item->key); fz_free(ctx, item); fz_lock(ctx, FZ_LOCK_ALLOC); } @@ -194,30 +188,21 @@ ensure_space(fz_context *ctx, unsigned int tofree) return count; } -void -fz_store_item(fz_context *ctx, fz_obj *key, void *val_, unsigned int itemsize) +void * +fz_store_item(fz_context *ctx, void *key, void *val_, unsigned int itemsize, fz_store_type *type) { fz_item *item = NULL; unsigned int size; fz_storable *val = (fz_storable *)val_; fz_store *store = ctx->store; - int indirect; - struct refkey refkey; + fz_store_hash hash = { NULL }; + int use_hash = 0; if (!store) - return; + return NULL; fz_var(item); - /* Form the key before we take the lock */ - indirect = fz_is_indirect(key); - if (indirect) - { - refkey.free = val->free; - refkey.num = fz_to_num(key); - refkey.gen = fz_to_gen(key); - } - /* If we fail for any reason, we swallow the exception and continue. * All that the above program will see is that we failed to store * the item. */ @@ -227,9 +212,16 @@ fz_store_item(fz_context *ctx, fz_obj *key, void *val_, unsigned int itemsize) } fz_catch(ctx) { - return; + return NULL; } + if (type->make_hash_key) + { + hash.free = val->free; + use_hash = type->make_hash_key(&hash, key); + } + + type->keep_key(ctx, key); fz_lock(ctx, FZ_LOCK_ALLOC); if (store->max != FZ_STORE_UNLIMITED) { @@ -242,34 +234,44 @@ fz_store_item(fz_context *ctx, fz_obj *key, void *val_, unsigned int itemsize) /* Failed to free any space */ fz_unlock(ctx, FZ_LOCK_ALLOC); fz_free(ctx, item); - return; + type->drop_key(ctx, key); + return NULL; } } } store->size += itemsize; - item->key = fz_keep_obj(key); + item->key = key; item->val = val; item->size = itemsize; item->next = NULL; + item->type = type; /* If we can index it fast, put it into the hash table */ - if (indirect) + if (use_hash) { - fz_unlock(ctx, FZ_LOCK_ALLOC); + fz_item *existing; + fz_try(ctx) { - fz_hash_insert(ctx, store->hash, &refkey, item); + /* May drop and retake the lock */ + existing = fz_hash_insert(ctx, store->hash, &hash, item); } fz_catch(ctx) { - fz_free(ctx, item); - fz_lock(ctx, FZ_LOCK_ALLOC); store->size -= itemsize; fz_unlock(ctx, FZ_LOCK_ALLOC); - return; + fz_free(ctx, item); + return NULL; + } + if (existing) + { + /* Take a new reference */ + existing->val->refs++; + fz_unlock(ctx, FZ_LOCK_ALLOC); + fz_free(ctx, item); + return existing->val; } - fz_lock(ctx, FZ_LOCK_ALLOC); } /* Now we can never fail, bump the ref */ if (val->refs > 0) @@ -283,15 +285,17 @@ fz_store_item(fz_context *ctx, fz_obj *key, void *val_, unsigned int itemsize) store->head = item; item->prev = NULL; fz_unlock(ctx, FZ_LOCK_ALLOC); + + return NULL; } void * -fz_find_item(fz_context *ctx, fz_store_free_fn *free, fz_obj *key) +fz_find_item(fz_context *ctx, fz_store_free_fn *free, void *key, fz_store_type *type) { - struct refkey refkey; fz_item *item; fz_store *store = ctx->store; - int indirect; + fz_store_hash hash = { NULL }; + int use_hash = 0; if (!store) return NULL; @@ -299,27 +303,24 @@ fz_find_item(fz_context *ctx, fz_store_free_fn *free, fz_obj *key) if (!key) return NULL; - /* Form the key before we take the lock */ - indirect = fz_is_indirect(key); - if (indirect) + if (type->make_hash_key) { - refkey.free = free; - refkey.num = fz_to_num(key); - refkey.gen = fz_to_gen(key); + hash.free = free; + use_hash = type->make_hash_key(&hash, key); } fz_lock(ctx, FZ_LOCK_ALLOC); - if (indirect) + if (use_hash) { /* We can find objects keyed on indirected objects quickly */ - item = fz_hash_find(ctx, store->hash, &refkey); + item = fz_hash_find(ctx, store->hash, &hash); } else { /* Others we have to hunt for slowly */ for (item = store->head; item; item = item->next) { - if (item->val->free == free && !fz_objcmp(item->key, key)) + if (item->val->free == free && !type->cmp_key(item->key, key)) break; } } @@ -355,35 +356,33 @@ fz_find_item(fz_context *ctx, fz_store_free_fn *free, fz_obj *key) } void -fz_remove_item(fz_context *ctx, fz_store_free_fn *free, fz_obj *key) +fz_remove_item(fz_context *ctx, fz_store_free_fn *free, void *key, fz_store_type *type) { - struct refkey refkey; fz_item *item; fz_store *store = ctx->store; - int drop, indirect; + int drop; + fz_store_hash hash; + int use_hash = 0; - /* Form the key before we take the lock */ - indirect = fz_is_indirect(key); - if (indirect) + if (type->make_hash_key) { - refkey.free = free; - refkey.num = fz_to_num(key); - refkey.gen = fz_to_gen(key); + hash.free = free; + use_hash = type->make_hash_key(&hash, key); } fz_lock(ctx, FZ_LOCK_ALLOC); - if (indirect) + if (use_hash) { /* We can find objects keyed on indirect objects quickly */ - item = fz_hash_find(ctx, store->hash, &refkey); + item = fz_hash_find(ctx, store->hash, &hash); if (item) - fz_hash_remove(ctx, store->hash, &refkey); + fz_hash_remove(ctx, store->hash, &hash); } else { /* Others we have to hunt for slowly */ for (item = store->head; item; item = item->next) - if (item->val->free == free && !fz_objcmp(item->key, key)) + if (item->val->free == free && !type->cmp_key(item->key, key)) break; } if (item) @@ -400,7 +399,7 @@ fz_remove_item(fz_context *ctx, fz_store_free_fn *free, fz_obj *key) fz_unlock(ctx, FZ_LOCK_ALLOC); if (drop) item->val->free(ctx, item->val); - fz_drop_obj(item->key); + type->drop_key(ctx, item->key); fz_free(ctx, item); } else @@ -425,7 +424,7 @@ fz_empty_store(fz_context *ctx) } fz_store * -fz_store_keep(fz_context *ctx) +fz_keep_store_context(fz_context *ctx) { if (ctx == NULL || ctx->store == NULL) return NULL; @@ -454,28 +453,26 @@ fz_drop_store_context(fz_context *ctx) } void -fz_debug_store(fz_context *ctx) +fz_print_store(fz_context *ctx, FILE *out) { fz_item *item, *next; fz_store *store = ctx->store; - printf("-- resource store contents --\n"); + fprintf(out, "-- resource store contents --\n"); fz_lock(ctx, FZ_LOCK_ALLOC); for (item = store->head; item; item = next) { next = item->next; - next->val->refs++; - printf("store[*][refs=%d][size=%d] ", item->val->refs, item->size); + if (next) + next->val->refs++; + fprintf(out, "store[*][refs=%d][size=%d] ", item->val->refs, item->size); fz_unlock(ctx, FZ_LOCK_ALLOC); - if (fz_is_indirect(item->key)) - { - printf("(%d %d R) ", fz_to_num(item->key), fz_to_gen(item->key)); - } else - fz_debug_obj(item->key); - printf(" = %p\n", item->val); + item->type->debug(item->key); + fprintf(out, " = %p\n", item->val); fz_lock(ctx, FZ_LOCK_ALLOC); - next->val->refs--; + if (next) + next->val->refs--; } fz_unlock(ctx, FZ_LOCK_ALLOC); } @@ -524,7 +521,7 @@ int fz_store_scavenge(fz_context *ctx, unsigned int size, int *phase) #ifdef DEBUG_SCAVENGING printf("Scavenging: store=%d size=%d phase=%d\n", store->size, size, *phase); - fz_debug_store(ctx); + fz_print_store(ctx, stderr); Memento_stats(); #endif do @@ -552,7 +549,7 @@ int fz_store_scavenge(fz_context *ctx, unsigned int size, int *phase) { #ifdef DEBUG_SCAVENGING printf("scavenged: store=%d\n", store->size); - fz_debug_store(ctx); + fz_print_store(ctx, stderr); Memento_stats(); #endif return 1; @@ -562,7 +559,7 @@ int fz_store_scavenge(fz_context *ctx, unsigned int size, int *phase) #ifdef DEBUG_SCAVENGING printf("scavenging failed\n"); - fz_debug_store(ctx); + fz_print_store(ctx, stderr); Memento_listBlocks(); #endif return 0; diff --git a/fitz/res_text.c b/fitz/res_text.c index cdfaaa98..643b4c9f 100644 --- a/fitz/res_text.c +++ b/fitz/res_text.c @@ -1,4 +1,4 @@ -#include "fitz.h" +#include "fitz-internal.h" fz_text * fz_new_text(fz_context *ctx, fz_font *font, fz_matrix trm, int wmode) @@ -118,23 +118,30 @@ fz_add_text(fz_context *ctx, fz_text *text, int gid, int ucs, float x, float y) text->len++; } -static int isxmlmeta(int c) +static int +isxmlmeta(int c) { return c < 32 || c >= 128 || c == '&' || c == '<' || c == '>' || c == '\'' || c == '"'; } -void fz_debug_text(fz_context *ctx, fz_text *text, int indent) +static void +do_print_text(FILE *out, fz_text *text, int indent) { int i, n; for (i = 0; i < text->len; i++) { for (n = 0; n < indent; n++) - putchar(' '); + fputc(' ', out); if (!isxmlmeta(text->items[i].ucs)) - printf("<g ucs=\"%c\" gid=\"%d\" x=\"%g\" y=\"%g\" />\n", + fprintf(out, "<g ucs=\"%c\" gid=\"%d\" x=\"%g\" y=\"%g\" />\n", text->items[i].ucs, text->items[i].gid, text->items[i].x, text->items[i].y); else - printf("<g ucs=\"U+%04X\" gid=\"%d\" x=\"%g\" y=\"%g\" />\n", + fprintf(out, "<g ucs=\"U+%04X\" gid=\"%d\" x=\"%g\" y=\"%g\" />\n", text->items[i].ucs, text->items[i].gid, text->items[i].x, text->items[i].y); } } + +void fz_print_text(fz_context *ctx, FILE *out, fz_text *text) +{ + do_print_text(out, text, 0); +} diff --git a/fitz/stm_buffer.c b/fitz/stm_buffer.c index 7f9d521d..4be0165a 100644 --- a/fitz/stm_buffer.c +++ b/fitz/stm_buffer.c @@ -1,4 +1,4 @@ -#include "fitz.h" +#include "fitz-internal.h" fz_buffer * fz_new_buffer(fz_context *ctx, int size) @@ -28,7 +28,12 @@ fz_buffer * fz_keep_buffer(fz_context *ctx, fz_buffer *buf) { if (buf) + { + if (buf->refs == 1 && buf->cap > buf->len+1) + fz_resize_buffer(ctx, buf, buf->len); buf->refs ++; + } + return buf; } @@ -58,3 +63,18 @@ fz_grow_buffer(fz_context *ctx, fz_buffer *buf) { fz_resize_buffer(ctx, buf, (buf->cap * 3) / 2); } + +void +fz_trim_buffer(fz_context *ctx, fz_buffer *buf) +{ + if (buf->cap > buf->len+1) + fz_resize_buffer(ctx, buf, buf->len); +} + +int +fz_buffer_storage(fz_context *ctx, fz_buffer *buf, unsigned char **datap) +{ + if (datap) + *datap = (buf ? buf->data : NULL); + return (buf ? buf->len : 0); +} diff --git a/fitz/stm_open.c b/fitz/stm_open.c index e634f729..1e303825 100644 --- a/fitz/stm_open.c +++ b/fitz/stm_open.c @@ -1,4 +1,4 @@ -#include "fitz.h" +#include "fitz-internal.h" fz_stream * fz_new_stream(fz_context *ctx, void *state, diff --git a/fitz/stm_read.c b/fitz/stm_read.c index 2066b14c..216d2207 100644 --- a/fitz/stm_read.c +++ b/fitz/stm_read.c @@ -1,4 +1,6 @@ -#include "fitz.h" +#include "fitz-internal.h" + +#define MIN_BOMB (100 << 20) int fz_read(fz_stream *stm, unsigned char *buf, int len) @@ -101,16 +103,15 @@ fz_read_all(fz_stream *stm, int initial) if (initial < 1024) initial = 1024; - buf = fz_new_buffer(ctx, initial); + buf = fz_new_buffer(ctx, initial+1); while (1) { if (buf->len == buf->cap) fz_grow_buffer(ctx, buf); - if (buf->len / 200 > initial) + if (buf->len >= MIN_BOMB && buf->len / 200 > initial) { - fz_drop_buffer(ctx, buf); fz_throw(ctx, "compression bomb detected"); } @@ -126,6 +127,7 @@ fz_read_all(fz_stream *stm, int initial) fz_drop_buffer(ctx, buf); fz_rethrow(ctx); } + fz_trim_buffer(ctx, buf); return buf; } @@ -216,7 +216,7 @@ static UIImage *renderPage(struct document *doc, int number, CGSize screenSize) ctm = fz_scale(scale.width, scale.height); bbox = (fz_bbox){0, 0, pageSize.width * scale.width, pageSize.height * scale.height}; - pix = fz_new_pixmap_with_rect(ctx, fz_device_rgb, bbox); + pix = fz_new_pixmap_with_bbox(ctx, fz_device_rgb, bbox); fz_clear_pixmap_with_value(ctx, pix, 255); dev = fz_new_draw_device(ctx, pix); @@ -253,7 +253,7 @@ static UIImage *renderTile(struct document *doc, int number, CGSize screenSize, rect.y1 = tileRect.origin.y + tileRect.size.height; bbox = fz_round_rect(rect); - pix = fz_new_pixmap_with_rect(ctx, fz_device_rgb, bbox); + pix = fz_new_pixmap_with_bbox(ctx, fz_device_rgb, bbox); fz_clear_pixmap_with_value(ctx, pix, 255); dev = fz_new_draw_device(ctx, pix); diff --git a/fitz/base_object.c b/pdf/base_object.c index 964c5bb4..460b89f2 100644 --- a/fitz/base_object.c +++ b/pdf/base_object.c @@ -1,28 +1,29 @@ -#include "fitz.h" - -typedef enum fz_objkind_e -{ - FZ_NULL, - FZ_BOOL, - FZ_INT, - FZ_REAL, - FZ_STRING, - FZ_NAME, - FZ_ARRAY, - FZ_DICT, - FZ_INDIRECT -} fz_objkind; +#include "fitz-internal.h" +#include "mupdf-internal.h" + +typedef enum pdf_objkind_e +{ + PDF_NULL, + PDF_BOOL, + PDF_INT, + PDF_REAL, + PDF_STRING, + PDF_NAME, + PDF_ARRAY, + PDF_DICT, + PDF_INDIRECT +} pdf_objkind; struct keyval { - fz_obj *k; - fz_obj *v; + pdf_obj *k; + pdf_obj *v; }; -struct fz_obj_s +struct pdf_obj_s { int refs; - fz_objkind kind; + pdf_objkind kind; fz_context *ctx; union { @@ -37,7 +38,7 @@ struct fz_obj_s struct { int len; int cap; - fz_obj **items; + pdf_obj **items; } a; struct { char sorted; @@ -54,259 +55,259 @@ struct fz_obj_s } u; }; -fz_obj * -fz_new_null(fz_context *ctx) +pdf_obj * +pdf_new_null(fz_context *ctx) { - fz_obj *obj; - obj = Memento_label(fz_malloc(ctx, sizeof(fz_obj)), "fz_obj(null)"); + pdf_obj *obj; + obj = Memento_label(fz_malloc(ctx, sizeof(pdf_obj)), "pdf_obj(null)"); obj->ctx = ctx; obj->refs = 1; - obj->kind = FZ_NULL; + obj->kind = PDF_NULL; return obj; } -fz_obj * -fz_new_bool(fz_context *ctx, int b) +pdf_obj * +pdf_new_bool(fz_context *ctx, int b) { - fz_obj *obj; - obj = Memento_label(fz_malloc(ctx, sizeof(fz_obj)), "fz_obj(bool)"); + pdf_obj *obj; + obj = Memento_label(fz_malloc(ctx, sizeof(pdf_obj)), "pdf_obj(bool)"); obj->ctx = ctx; obj->refs = 1; - obj->kind = FZ_BOOL; + obj->kind = PDF_BOOL; obj->u.b = b; return obj; } -fz_obj * -fz_new_int(fz_context *ctx, int i) +pdf_obj * +pdf_new_int(fz_context *ctx, int i) { - fz_obj *obj; - obj = Memento_label(fz_malloc(ctx, sizeof(fz_obj)), "fz_obj(int)"); + pdf_obj *obj; + obj = Memento_label(fz_malloc(ctx, sizeof(pdf_obj)), "pdf_obj(int)"); obj->ctx = ctx; obj->refs = 1; - obj->kind = FZ_INT; + obj->kind = PDF_INT; obj->u.i = i; return obj; } -fz_obj * -fz_new_real(fz_context *ctx, float f) +pdf_obj * +pdf_new_real(fz_context *ctx, float f) { - fz_obj *obj; - obj = Memento_label(fz_malloc(ctx, sizeof(fz_obj)), "fz_obj(real)"); + pdf_obj *obj; + obj = Memento_label(fz_malloc(ctx, sizeof(pdf_obj)), "pdf_obj(real)"); obj->ctx = ctx; obj->refs = 1; - obj->kind = FZ_REAL; + obj->kind = PDF_REAL; obj->u.f = f; return obj; } -fz_obj * -fz_new_string(fz_context *ctx, char *str, int len) +pdf_obj * +pdf_new_string(fz_context *ctx, char *str, int len) { - fz_obj *obj; - obj = Memento_label(fz_malloc(ctx, offsetof(fz_obj, u.s.buf) + len + 1), "fz_obj(string)"); + pdf_obj *obj; + obj = Memento_label(fz_malloc(ctx, offsetof(pdf_obj, u.s.buf) + len + 1), "pdf_obj(string)"); obj->ctx = ctx; obj->refs = 1; - obj->kind = FZ_STRING; + obj->kind = PDF_STRING; obj->u.s.len = len; memcpy(obj->u.s.buf, str, len); obj->u.s.buf[len] = '\0'; return obj; } -fz_obj * +pdf_obj * fz_new_name(fz_context *ctx, char *str) { - fz_obj *obj; - obj = Memento_label(fz_malloc(ctx, offsetof(fz_obj, u.n) + strlen(str) + 1), "fz_obj(name)"); + pdf_obj *obj; + obj = Memento_label(fz_malloc(ctx, offsetof(pdf_obj, u.n) + strlen(str) + 1), "pdf_obj(name)"); obj->ctx = ctx; obj->refs = 1; - obj->kind = FZ_NAME; + obj->kind = PDF_NAME; strcpy(obj->u.n, str); return obj; } -fz_obj * -fz_new_indirect(fz_context *ctx, int num, int gen, void *xref) +pdf_obj * +pdf_new_indirect(fz_context *ctx, int num, int gen, void *xref) { - fz_obj *obj; - obj = Memento_label(fz_malloc(ctx, sizeof(fz_obj)), "fz_obj(indirect)"); + pdf_obj *obj; + obj = Memento_label(fz_malloc(ctx, sizeof(pdf_obj)), "pdf_obj(indirect)"); obj->ctx = ctx; obj->refs = 1; - obj->kind = FZ_INDIRECT; + obj->kind = PDF_INDIRECT; obj->u.r.num = num; obj->u.r.gen = gen; obj->u.r.xref = xref; return obj; } -fz_obj * -fz_keep_obj(fz_obj *obj) +pdf_obj * +pdf_keep_obj(pdf_obj *obj) { assert(obj); obj->refs ++; return obj; } -int fz_is_indirect(fz_obj *obj) +int pdf_is_indirect(pdf_obj *obj) { - return obj ? obj->kind == FZ_INDIRECT : 0; + return obj ? obj->kind == PDF_INDIRECT : 0; } #define RESOLVE(obj) \ do { \ - if (obj && obj->kind == FZ_INDIRECT) \ + if (obj && obj->kind == PDF_INDIRECT) \ {\ fz_assert_lock_not_held(obj->ctx, FZ_LOCK_FILE); \ - obj = fz_resolve_indirect(obj); \ + obj = pdf_resolve_indirect(obj); \ } \ } while (0) -int fz_is_null(fz_obj *obj) +int pdf_is_null(pdf_obj *obj) { RESOLVE(obj); - return obj ? obj->kind == FZ_NULL : 0; + return obj ? obj->kind == PDF_NULL : 0; } -int fz_is_bool(fz_obj *obj) +int pdf_is_bool(pdf_obj *obj) { RESOLVE(obj); - return obj ? obj->kind == FZ_BOOL : 0; + return obj ? obj->kind == PDF_BOOL : 0; } -int fz_is_int(fz_obj *obj) +int pdf_is_int(pdf_obj *obj) { RESOLVE(obj); - return obj ? obj->kind == FZ_INT : 0; + return obj ? obj->kind == PDF_INT : 0; } -int fz_is_real(fz_obj *obj) +int pdf_is_real(pdf_obj *obj) { RESOLVE(obj); - return obj ? obj->kind == FZ_REAL : 0; + return obj ? obj->kind == PDF_REAL : 0; } -int fz_is_string(fz_obj *obj) +int pdf_is_string(pdf_obj *obj) { RESOLVE(obj); - return obj ? obj->kind == FZ_STRING : 0; + return obj ? obj->kind == PDF_STRING : 0; } -int fz_is_name(fz_obj *obj) +int pdf_is_name(pdf_obj *obj) { RESOLVE(obj); - return obj ? obj->kind == FZ_NAME : 0; + return obj ? obj->kind == PDF_NAME : 0; } -int fz_is_array(fz_obj *obj) +int pdf_is_array(pdf_obj *obj) { RESOLVE(obj); - return obj ? obj->kind == FZ_ARRAY : 0; + return obj ? obj->kind == PDF_ARRAY : 0; } -int fz_is_dict(fz_obj *obj) +int pdf_is_dict(pdf_obj *obj) { RESOLVE(obj); - return obj ? obj->kind == FZ_DICT : 0; + return obj ? obj->kind == PDF_DICT : 0; } -int fz_to_bool(fz_obj *obj) +int pdf_to_bool(pdf_obj *obj) { RESOLVE(obj); if (!obj) return 0; - return obj->kind == FZ_BOOL ? obj->u.b : 0; + return obj->kind == PDF_BOOL ? obj->u.b : 0; } -int fz_to_int(fz_obj *obj) +int pdf_to_int(pdf_obj *obj) { RESOLVE(obj); if (!obj) return 0; - if (obj->kind == FZ_INT) + if (obj->kind == PDF_INT) return obj->u.i; - if (obj->kind == FZ_REAL) + if (obj->kind == PDF_REAL) return (int)(obj->u.f + 0.5f); /* No roundf in MSVC */ return 0; } -float fz_to_real(fz_obj *obj) +float pdf_to_real(pdf_obj *obj) { RESOLVE(obj); if (!obj) return 0; - if (obj->kind == FZ_REAL) + if (obj->kind == PDF_REAL) return obj->u.f; - if (obj->kind == FZ_INT) + if (obj->kind == PDF_INT) return obj->u.i; return 0; } -char *fz_to_name(fz_obj *obj) +char *pdf_to_name(pdf_obj *obj) { RESOLVE(obj); - if (!obj || obj->kind != FZ_NAME) + if (!obj || obj->kind != PDF_NAME) return ""; return obj->u.n; } -char *fz_to_str_buf(fz_obj *obj) +char *pdf_to_str_buf(pdf_obj *obj) { RESOLVE(obj); - if (!obj || obj->kind != FZ_STRING) + if (!obj || obj->kind != PDF_STRING) return ""; return obj->u.s.buf; } -int fz_to_str_len(fz_obj *obj) +int pdf_to_str_len(pdf_obj *obj) { RESOLVE(obj); - if (!obj || obj->kind != FZ_STRING) + if (!obj || obj->kind != PDF_STRING) return 0; return obj->u.s.len; } /* for use by pdf_crypt_obj_imp to decrypt AES string in place */ -void fz_set_str_len(fz_obj *obj, int newlen) +void pdf_set_str_len(pdf_obj *obj, int newlen) { RESOLVE(obj); - if (!obj || obj->kind != FZ_STRING) + if (!obj || obj->kind != PDF_STRING) return; /* This should never happen */ if (newlen > obj->u.s.len) return; /* This should never happen */ obj->u.s.len = newlen; } -fz_obj *fz_to_dict(fz_obj *obj) +pdf_obj *pdf_to_dict(pdf_obj *obj) { RESOLVE(obj); - return (obj && obj->kind == FZ_DICT ? obj : NULL); + return (obj && obj->kind == PDF_DICT ? obj : NULL); } -int fz_to_num(fz_obj *obj) +int pdf_to_num(pdf_obj *obj) { - if (!obj || obj->kind != FZ_INDIRECT) + if (!obj || obj->kind != PDF_INDIRECT) return 0; return obj->u.r.num; } -int fz_to_gen(fz_obj *obj) +int pdf_to_gen(pdf_obj *obj) { - if (!obj || obj->kind != FZ_INDIRECT) + if (!obj || obj->kind != PDF_INDIRECT) return 0; return obj->u.r.gen; } -void *fz_get_indirect_document(fz_obj *obj) +void *pdf_get_indirect_document(pdf_obj *obj) { - if (!obj || obj->kind != FZ_INDIRECT) + if (!obj || obj->kind != PDF_INDIRECT) return NULL; return obj->u.r.xref; } int -fz_objcmp(fz_obj *a, fz_obj *b) +pdf_objcmp(pdf_obj *a, pdf_obj *b) { int i; @@ -321,23 +322,23 @@ fz_objcmp(fz_obj *a, fz_obj *b) switch (a->kind) { - case FZ_NULL: + case PDF_NULL: return 0; - case FZ_BOOL: + case PDF_BOOL: return a->u.b - b->u.b; - case FZ_INT: + case PDF_INT: return a->u.i - b->u.i; - case FZ_REAL: + case PDF_REAL: if (a->u.f < b->u.f) return -1; if (a->u.f > b->u.f) return 1; return 0; - case FZ_STRING: + case PDF_STRING: if (a->u.s.len < b->u.s.len) { if (memcmp(a->u.s.buf, b->u.s.buf, a->u.s.len) <= 0) @@ -352,30 +353,30 @@ fz_objcmp(fz_obj *a, fz_obj *b) } return memcmp(a->u.s.buf, b->u.s.buf, a->u.s.len); - case FZ_NAME: + case PDF_NAME: return strcmp(a->u.n, b->u.n); - case FZ_INDIRECT: + case PDF_INDIRECT: if (a->u.r.num == b->u.r.num) return a->u.r.gen - b->u.r.gen; return a->u.r.num - b->u.r.num; - case FZ_ARRAY: + case PDF_ARRAY: if (a->u.a.len != b->u.a.len) return a->u.a.len - b->u.a.len; for (i = 0; i < a->u.a.len; i++) - if (fz_objcmp(a->u.a.items[i], b->u.a.items[i])) + if (pdf_objcmp(a->u.a.items[i], b->u.a.items[i])) return 1; return 0; - case FZ_DICT: + case PDF_DICT: if (a->u.d.len != b->u.d.len) return a->u.d.len - b->u.d.len; for (i = 0; i < a->u.d.len; i++) { - if (fz_objcmp(a->u.d.items[i].k, b->u.d.items[i].k)) + if (pdf_objcmp(a->u.d.items[i].k, b->u.d.items[i].k)) return 1; - if (fz_objcmp(a->u.d.items[i].v, b->u.d.items[i].v)) + if (pdf_objcmp(a->u.d.items[i].v, b->u.d.items[i].v)) return 1; } return 0; @@ -385,42 +386,42 @@ fz_objcmp(fz_obj *a, fz_obj *b) } static char * -fz_objkindstr(fz_obj *obj) +pdf_objkindstr(pdf_obj *obj) { if (!obj) return "<NULL>"; switch (obj->kind) { - case FZ_NULL: return "null"; - case FZ_BOOL: return "boolean"; - case FZ_INT: return "integer"; - case FZ_REAL: return "real"; - case FZ_STRING: return "string"; - case FZ_NAME: return "name"; - case FZ_ARRAY: return "array"; - case FZ_DICT: return "dictionary"; - case FZ_INDIRECT: return "reference"; + case PDF_NULL: return "null"; + case PDF_BOOL: return "boolean"; + case PDF_INT: return "integer"; + case PDF_REAL: return "real"; + case PDF_STRING: return "string"; + case PDF_NAME: return "name"; + case PDF_ARRAY: return "array"; + case PDF_DICT: return "dictionary"; + case PDF_INDIRECT: return "reference"; } return "<unknown>"; } -fz_obj * -fz_new_array(fz_context *ctx, int initialcap) +pdf_obj * +pdf_new_array(fz_context *ctx, int initialcap) { - fz_obj *obj; + pdf_obj *obj; int i; - obj = Memento_label(fz_malloc(ctx, sizeof(fz_obj)), "fz_obj(array)"); + obj = Memento_label(fz_malloc(ctx, sizeof(pdf_obj)), "pdf_obj(array)"); obj->ctx = ctx; obj->refs = 1; - obj->kind = FZ_ARRAY; + obj->kind = PDF_ARRAY; obj->u.a.len = 0; obj->u.a.cap = initialcap > 1 ? initialcap : 6; fz_try(ctx) { - obj->u.a.items = Memento_label(fz_malloc_array(ctx, obj->u.a.cap, sizeof(fz_obj*)), "fz_obj(array items)"); + obj->u.a.items = Memento_label(fz_malloc_array(ctx, obj->u.a.cap, sizeof(pdf_obj*)), "pdf_obj(array items)"); } fz_catch(ctx) { @@ -434,51 +435,51 @@ fz_new_array(fz_context *ctx, int initialcap) } static void -fz_array_grow(fz_obj *obj) +pdf_array_grow(pdf_obj *obj) { int i; obj->u.a.cap = (obj->u.a.cap * 3) / 2; - obj->u.a.items = fz_resize_array(obj->ctx, obj->u.a.items, obj->u.a.cap, sizeof(fz_obj*)); + obj->u.a.items = fz_resize_array(obj->ctx, obj->u.a.items, obj->u.a.cap, sizeof(pdf_obj*)); for (i = obj->u.a.len ; i < obj->u.a.cap; i++) obj->u.a.items[i] = NULL; } -fz_obj * -fz_copy_array(fz_context *ctx, fz_obj *obj) +pdf_obj * +pdf_copy_array(fz_context *ctx, pdf_obj *obj) { - fz_obj *arr; + pdf_obj *arr; int i; int n; RESOLVE(obj); - if (!obj || obj->kind != FZ_ARRAY) - fz_warn(ctx, "assert: not an array (%s)", fz_objkindstr(obj)); + if (!obj || obj->kind != PDF_ARRAY) + fz_warn(ctx, "assert: not an array (%s)", pdf_objkindstr(obj)); - arr = fz_new_array(ctx, fz_array_len(obj)); - n = fz_array_len(obj); + arr = pdf_new_array(ctx, pdf_array_len(obj)); + n = pdf_array_len(obj); for (i = 0; i < n; i++) - fz_array_push(arr, fz_array_get(obj, i)); + pdf_array_push(arr, pdf_array_get(obj, i)); return arr; } int -fz_array_len(fz_obj *obj) +pdf_array_len(pdf_obj *obj) { RESOLVE(obj); - if (!obj || obj->kind != FZ_ARRAY) + if (!obj || obj->kind != PDF_ARRAY) return 0; return obj->u.a.len; } -fz_obj * -fz_array_get(fz_obj *obj, int i) +pdf_obj * +pdf_array_get(pdf_obj *obj, int i) { RESOLVE(obj); - if (!obj || obj->kind != FZ_ARRAY) + if (!obj || obj->kind != PDF_ARRAY) return NULL; if (i < 0 || i >= obj->u.a.len) @@ -488,14 +489,14 @@ fz_array_get(fz_obj *obj, int i) } void -fz_array_put(fz_obj *obj, int i, fz_obj *item) +pdf_array_put(pdf_obj *obj, int i, pdf_obj *item) { RESOLVE(obj); if (!obj) return; /* Can't warn :( */ - if (obj->kind != FZ_ARRAY) - fz_warn(obj->ctx, "assert: not an array (%s)", fz_objkindstr(obj)); + if (obj->kind != PDF_ARRAY) + fz_warn(obj->ctx, "assert: not an array (%s)", pdf_objkindstr(obj)); else if (i < 0) fz_warn(obj->ctx, "assert: index %d < 0", i); else if (i >= obj->u.a.len) @@ -503,55 +504,55 @@ fz_array_put(fz_obj *obj, int i, fz_obj *item) else { if (obj->u.a.items[i]) - fz_drop_obj(obj->u.a.items[i]); - obj->u.a.items[i] = fz_keep_obj(item); + pdf_drop_obj(obj->u.a.items[i]); + obj->u.a.items[i] = pdf_keep_obj(item); } } void -fz_array_push(fz_obj *obj, fz_obj *item) +pdf_array_push(pdf_obj *obj, pdf_obj *item) { RESOLVE(obj); if (!obj) return; /* Can't warn :( */ - if (obj->kind != FZ_ARRAY) - fz_warn(obj->ctx, "assert: not an array (%s)", fz_objkindstr(obj)); + if (obj->kind != PDF_ARRAY) + fz_warn(obj->ctx, "assert: not an array (%s)", pdf_objkindstr(obj)); else { if (obj->u.a.len + 1 > obj->u.a.cap) - fz_array_grow(obj); - obj->u.a.items[obj->u.a.len] = fz_keep_obj(item); + pdf_array_grow(obj); + obj->u.a.items[obj->u.a.len] = pdf_keep_obj(item); obj->u.a.len++; } } void -fz_array_insert(fz_obj *obj, fz_obj *item) +pdf_array_insert(pdf_obj *obj, pdf_obj *item) { RESOLVE(obj); if (!obj) return; /* Can't warn :( */ - if (obj->kind != FZ_ARRAY) - fz_warn(obj->ctx, "assert: not an array (%s)", fz_objkindstr(obj)); + if (obj->kind != PDF_ARRAY) + fz_warn(obj->ctx, "assert: not an array (%s)", pdf_objkindstr(obj)); else { if (obj->u.a.len + 1 > obj->u.a.cap) - fz_array_grow(obj); - memmove(obj->u.a.items + 1, obj->u.a.items, obj->u.a.len * sizeof(fz_obj*)); - obj->u.a.items[0] = fz_keep_obj(item); + pdf_array_grow(obj); + memmove(obj->u.a.items + 1, obj->u.a.items, obj->u.a.len * sizeof(pdf_obj*)); + obj->u.a.items[0] = pdf_keep_obj(item); obj->u.a.len++; } } int -fz_array_contains(fz_obj *arr, fz_obj *obj) +pdf_array_contains(pdf_obj *arr, pdf_obj *obj) { int i; - for (i = 0; i < fz_array_len(arr); i++) - if (!fz_objcmp(fz_array_get(arr, i), obj)) + for (i = 0; i < pdf_array_len(arr); i++) + if (!pdf_objcmp(pdf_array_get(arr, i), obj)) return 1; return 0; @@ -563,19 +564,19 @@ static int keyvalcmp(const void *ap, const void *bp) { const struct keyval *a = ap; const struct keyval *b = bp; - return strcmp(fz_to_name(a->k), fz_to_name(b->k)); + return strcmp(pdf_to_name(a->k), pdf_to_name(b->k)); } -fz_obj * -fz_new_dict(fz_context *ctx, int initialcap) +pdf_obj * +pdf_new_dict(fz_context *ctx, int initialcap) { - fz_obj *obj; + pdf_obj *obj; int i; - obj = Memento_label(fz_malloc(ctx, sizeof(fz_obj)), "fz_obj(dict)"); + obj = Memento_label(fz_malloc(ctx, sizeof(pdf_obj)), "pdf_obj(dict)"); obj->ctx = ctx; obj->refs = 1; - obj->kind = FZ_DICT; + obj->kind = PDF_DICT; obj->u.d.sorted = 0; obj->u.d.marked = 0; @@ -584,7 +585,7 @@ fz_new_dict(fz_context *ctx, int initialcap) fz_try(ctx) { - obj->u.d.items = Memento_label(fz_malloc_array(ctx, obj->u.d.cap, sizeof(struct keyval)), "fz_obj(dict items)"); + obj->u.d.items = Memento_label(fz_malloc_array(ctx, obj->u.d.cap, sizeof(struct keyval)), "pdf_obj(dict items)"); } fz_catch(ctx) { @@ -601,7 +602,7 @@ fz_new_dict(fz_context *ctx, int initialcap) } static void -fz_dict_grow(fz_obj *obj) +pdf_dict_grow(pdf_obj *obj) { int i; @@ -615,38 +616,38 @@ fz_dict_grow(fz_obj *obj) } } -fz_obj * -fz_copy_dict(fz_context *ctx, fz_obj *obj) +pdf_obj * +pdf_copy_dict(fz_context *ctx, pdf_obj *obj) { - fz_obj *dict; + pdf_obj *dict; int i, n; RESOLVE(obj); - if (obj && obj->kind != FZ_DICT) - fz_warn(ctx, "assert: not a dict (%s)", fz_objkindstr(obj)); + if (obj && obj->kind != PDF_DICT) + fz_warn(ctx, "assert: not a dict (%s)", pdf_objkindstr(obj)); - n = fz_dict_len(obj); - dict = fz_new_dict(ctx, n); + n = pdf_dict_len(obj); + dict = pdf_new_dict(ctx, n); for (i = 0; i < n; i++) - fz_dict_put(dict, fz_dict_get_key(obj, i), fz_dict_get_val(obj, i)); + fz_dict_put(dict, pdf_dict_get_key(obj, i), pdf_dict_get_val(obj, i)); return dict; } int -fz_dict_len(fz_obj *obj) +pdf_dict_len(pdf_obj *obj) { RESOLVE(obj); - if (!obj || obj->kind != FZ_DICT) + if (!obj || obj->kind != PDF_DICT) return 0; return obj->u.d.len; } -fz_obj * -fz_dict_get_key(fz_obj *obj, int i) +pdf_obj * +pdf_dict_get_key(pdf_obj *obj, int i) { RESOLVE(obj); - if (!obj || obj->kind != FZ_DICT) + if (!obj || obj->kind != PDF_DICT) return NULL; if (i < 0 || i >= obj->u.d.len) @@ -655,11 +656,11 @@ fz_dict_get_key(fz_obj *obj, int i) return obj->u.d.items[i].k; } -fz_obj * -fz_dict_get_val(fz_obj *obj, int i) +pdf_obj * +pdf_dict_get_val(pdf_obj *obj, int i) { RESOLVE(obj); - if (!obj || obj->kind != FZ_DICT) + if (!obj || obj->kind != PDF_DICT) return NULL; if (i < 0 || i >= obj->u.d.len) @@ -669,14 +670,14 @@ fz_dict_get_val(fz_obj *obj, int i) } static int -fz_dict_finds(fz_obj *obj, char *key, int *location) +pdf_dict_finds(pdf_obj *obj, char *key, int *location) { if (obj->u.d.sorted && obj->u.d.len > 0) { int l = 0; int r = obj->u.d.len - 1; - if (strcmp(fz_to_name(obj->u.d.items[r].k), key) < 0) + if (strcmp(pdf_to_name(obj->u.d.items[r].k), key) < 0) { if (location) *location = r + 1; @@ -686,7 +687,7 @@ fz_dict_finds(fz_obj *obj, char *key, int *location) while (l <= r) { int m = (l + r) >> 1; - int c = -strcmp(fz_to_name(obj->u.d.items[m].k), key); + int c = -strcmp(pdf_to_name(obj->u.d.items[m].k), key); if (c < 0) r = m - 1; else if (c > 0) @@ -703,7 +704,7 @@ fz_dict_finds(fz_obj *obj, char *key, int *location) { int i; for (i = 0; i < obj->u.d.len; i++) - if (strcmp(fz_to_name(obj->u.d.items[i].k), key) == 0) + if (strcmp(pdf_to_name(obj->u.d.items[i].k), key) == 0) return i; if (location) @@ -713,62 +714,62 @@ fz_dict_finds(fz_obj *obj, char *key, int *location) return -1; } -fz_obj * -fz_dict_gets(fz_obj *obj, char *key) +pdf_obj * +pdf_dict_gets(pdf_obj *obj, char *key) { int i; RESOLVE(obj); - if (!obj || obj->kind != FZ_DICT) + if (!obj || obj->kind != PDF_DICT) return NULL; - i = fz_dict_finds(obj, key, NULL); + i = pdf_dict_finds(obj, key, NULL); if (i >= 0) return obj->u.d.items[i].v; return NULL; } -fz_obj * -fz_dict_get(fz_obj *obj, fz_obj *key) +pdf_obj * +pdf_dict_get(pdf_obj *obj, pdf_obj *key) { - if (!key || key->kind != FZ_NAME) + if (!key || key->kind != PDF_NAME) return NULL; - return fz_dict_gets(obj, fz_to_name(key)); + return pdf_dict_gets(obj, pdf_to_name(key)); } -fz_obj * -fz_dict_getsa(fz_obj *obj, char *key, char *abbrev) +pdf_obj * +pdf_dict_getsa(pdf_obj *obj, char *key, char *abbrev) { - fz_obj *v; - v = fz_dict_gets(obj, key); + pdf_obj *v; + v = pdf_dict_gets(obj, key); if (v) return v; - return fz_dict_gets(obj, abbrev); + return pdf_dict_gets(obj, abbrev); } void -fz_dict_put(fz_obj *obj, fz_obj *key, fz_obj *val) +fz_dict_put(pdf_obj *obj, pdf_obj *key, pdf_obj *val) { int location; char *s; int i; RESOLVE(obj); - if (!obj || obj->kind != FZ_DICT) + if (!obj || obj->kind != PDF_DICT) { - fz_warn(obj->ctx, "assert: not a dict (%s)", fz_objkindstr(obj)); + fz_warn(obj->ctx, "assert: not a dict (%s)", pdf_objkindstr(obj)); return; } RESOLVE(key); - if (!key || key->kind != FZ_NAME) + if (!key || key->kind != PDF_NAME) { - fz_warn(obj->ctx, "assert: key is not a name (%s)", fz_objkindstr(obj)); + fz_warn(obj->ctx, "assert: key is not a name (%s)", pdf_objkindstr(obj)); return; } else - s = fz_to_name(key); + s = pdf_to_name(key); if (!val) { @@ -777,18 +778,18 @@ fz_dict_put(fz_obj *obj, fz_obj *key, fz_obj *val) } if (obj->u.d.len > 100 && !obj->u.d.sorted) - fz_sort_dict(obj); + pdf_sort_dict(obj); - i = fz_dict_finds(obj, s, &location); + i = pdf_dict_finds(obj, s, &location); if (i >= 0 && i < obj->u.d.len) { - fz_drop_obj(obj->u.d.items[i].v); - obj->u.d.items[i].v = fz_keep_obj(val); + pdf_drop_obj(obj->u.d.items[i].v); + obj->u.d.items[i].v = pdf_keep_obj(val); } else { if (obj->u.d.len + 1 > obj->u.d.cap) - fz_dict_grow(obj); + pdf_dict_grow(obj); i = location; if (obj->u.d.sorted && obj->u.d.len > 0) @@ -796,34 +797,34 @@ fz_dict_put(fz_obj *obj, fz_obj *key, fz_obj *val) &obj->u.d.items[i], (obj->u.d.len - i) * sizeof(struct keyval)); - obj->u.d.items[i].k = fz_keep_obj(key); - obj->u.d.items[i].v = fz_keep_obj(val); + obj->u.d.items[i].k = pdf_keep_obj(key); + obj->u.d.items[i].v = pdf_keep_obj(val); obj->u.d.len ++; } } void -fz_dict_puts(fz_obj *obj, char *key, fz_obj *val) +pdf_dict_puts(pdf_obj *obj, char *key, pdf_obj *val) { - fz_obj *keyobj = fz_new_name(obj->ctx, key); + pdf_obj *keyobj = fz_new_name(obj->ctx, key); fz_dict_put(obj, keyobj, val); - fz_drop_obj(keyobj); + pdf_drop_obj(keyobj); } void -fz_dict_dels(fz_obj *obj, char *key) +pdf_dict_dels(pdf_obj *obj, char *key) { RESOLVE(obj); - if (!obj || obj->kind != FZ_DICT) - fz_warn(obj->ctx, "assert: not a dict (%s)", fz_objkindstr(obj)); + if (!obj || obj->kind != PDF_DICT) + fz_warn(obj->ctx, "assert: not a dict (%s)", pdf_objkindstr(obj)); else { - int i = fz_dict_finds(obj, key, NULL); + int i = pdf_dict_finds(obj, key, NULL); if (i >= 0) { - fz_drop_obj(obj->u.d.items[i].k); - fz_drop_obj(obj->u.d.items[i].v); + pdf_drop_obj(obj->u.d.items[i].k); + pdf_drop_obj(obj->u.d.items[i].v); obj->u.d.sorted = 0; obj->u.d.items[i] = obj->u.d.items[obj->u.d.len-1]; obj->u.d.len --; @@ -832,20 +833,20 @@ fz_dict_dels(fz_obj *obj, char *key) } void -fz_dict_del(fz_obj *obj, fz_obj *key) +pdf_dict_del(pdf_obj *obj, pdf_obj *key) { RESOLVE(key); - if (!key || key->kind != FZ_NAME) - fz_warn(obj->ctx, "assert: key is not a name (%s)", fz_objkindstr(obj)); + if (!key || key->kind != PDF_NAME) + fz_warn(obj->ctx, "assert: key is not a name (%s)", pdf_objkindstr(obj)); else - fz_dict_dels(obj, key->u.n); + pdf_dict_dels(obj, key->u.n); } void -fz_sort_dict(fz_obj *obj) +pdf_sort_dict(pdf_obj *obj) { RESOLVE(obj); - if (!obj || obj->kind != FZ_DICT) + if (!obj || obj->kind != PDF_DICT) return; if (!obj->u.d.sorted) { @@ -855,20 +856,20 @@ fz_sort_dict(fz_obj *obj) } int -fz_dict_marked(fz_obj *obj) +pdf_dict_marked(pdf_obj *obj) { RESOLVE(obj); - if (!obj || obj->kind != FZ_DICT) + if (!obj || obj->kind != PDF_DICT) return 0; return obj->u.d.marked; } int -fz_dict_mark(fz_obj *obj) +pdf_dict_mark(pdf_obj *obj) { int marked; RESOLVE(obj); - if (!obj || obj->kind != FZ_DICT) + if (!obj || obj->kind != PDF_DICT) return 0; marked = obj->u.d.marked; obj->u.d.marked = 1; @@ -876,37 +877,37 @@ fz_dict_mark(fz_obj *obj) } void -fz_dict_unmark(fz_obj *obj) +pdf_dict_unmark(pdf_obj *obj) { RESOLVE(obj); - if (!obj || obj->kind != FZ_DICT) + if (!obj || obj->kind != PDF_DICT) return; obj->u.d.marked = 0; } static void -fz_free_array(fz_obj *obj) +pdf_free_array(pdf_obj *obj) { int i; for (i = 0; i < obj->u.a.len; i++) if (obj->u.a.items[i]) - fz_drop_obj(obj->u.a.items[i]); + pdf_drop_obj(obj->u.a.items[i]); fz_free(obj->ctx, obj->u.a.items); fz_free(obj->ctx, obj); } static void -fz_free_dict(fz_obj *obj) +pdf_free_dict(pdf_obj *obj) { int i; for (i = 0; i < obj->u.d.len; i++) { if (obj->u.d.items[i].k) - fz_drop_obj(obj->u.d.items[i].k); + pdf_drop_obj(obj->u.d.items[i].k); if (obj->u.d.items[i].v) - fz_drop_obj(obj->u.d.items[i].v); + pdf_drop_obj(obj->u.d.items[i].v); } fz_free(obj->ctx, obj->u.d.items); @@ -914,16 +915,16 @@ fz_free_dict(fz_obj *obj) } void -fz_drop_obj(fz_obj *obj) +pdf_drop_obj(pdf_obj *obj) { if (!obj) return; if (--obj->refs) return; - if (obj->kind == FZ_ARRAY) - fz_free_array(obj); - else if (obj->kind == FZ_DICT) - fz_free_dict(obj); + if (obj->kind == PDF_ARRAY) + pdf_free_array(obj); + else if (obj->kind == PDF_DICT) + pdf_free_dict(obj); else fz_free(obj->ctx, obj); } @@ -942,7 +943,7 @@ struct fmt int last; }; -static void fmt_obj(struct fmt *fmt, fz_obj *obj); +static void fmt_obj(struct fmt *fmt, pdf_obj *obj); static inline int iswhite(int ch) { @@ -1006,10 +1007,10 @@ static inline void fmt_sep(struct fmt *fmt) fmt->sep = 1; } -static void fmt_str(struct fmt *fmt, fz_obj *obj) +static void fmt_str(struct fmt *fmt, pdf_obj *obj) { - char *s = fz_to_str_buf(obj); - int n = fz_to_str_len(obj); + char *s = pdf_to_str_buf(obj); + int n = pdf_to_str_len(obj); int i, c; fmt_putc(fmt, '('); @@ -1042,10 +1043,10 @@ static void fmt_str(struct fmt *fmt, fz_obj *obj) fmt_putc(fmt, ')'); } -static void fmt_hex(struct fmt *fmt, fz_obj *obj) +static void fmt_hex(struct fmt *fmt, pdf_obj *obj) { - char *s = fz_to_str_buf(obj); - int n = fz_to_str_len(obj); + char *s = pdf_to_str_buf(obj); + int n = pdf_to_str_len(obj); int i, b, c; fmt_putc(fmt, '<'); @@ -1059,9 +1060,9 @@ static void fmt_hex(struct fmt *fmt, fz_obj *obj) fmt_putc(fmt, '>'); } -static void fmt_name(struct fmt *fmt, fz_obj *obj) +static void fmt_name(struct fmt *fmt, pdf_obj *obj) { - unsigned char *s = (unsigned char *) fz_to_name(obj); + unsigned char *s = (unsigned char *) pdf_to_name(obj); int i, c; fmt_putc(fmt, '/'); @@ -1084,15 +1085,15 @@ static void fmt_name(struct fmt *fmt, fz_obj *obj) } } -static void fmt_array(struct fmt *fmt, fz_obj *obj) +static void fmt_array(struct fmt *fmt, pdf_obj *obj) { int i, n; - n = fz_array_len(obj); + n = pdf_array_len(obj); if (fmt->tight) { fmt_putc(fmt, '['); for (i = 0; i < n; i++) { - fmt_obj(fmt, fz_array_get(obj, i)); + fmt_obj(fmt, pdf_array_get(obj, i)); fmt_sep(fmt); } fmt_putc(fmt, ']'); @@ -1104,7 +1105,7 @@ static void fmt_array(struct fmt *fmt, fz_obj *obj) fmt_putc(fmt, '\n'); fmt_indent(fmt); } - fmt_obj(fmt, fz_array_get(obj, i)); + fmt_obj(fmt, pdf_array_get(obj, i)); fmt_putc(fmt, ' '); } fmt_putc(fmt, ']'); @@ -1112,18 +1113,18 @@ static void fmt_array(struct fmt *fmt, fz_obj *obj) } } -static void fmt_dict(struct fmt *fmt, fz_obj *obj) +static void fmt_dict(struct fmt *fmt, pdf_obj *obj) { int i, n; - fz_obj *key, *val; + pdf_obj *key, *val; - n = fz_dict_len(obj); + n = pdf_dict_len(obj); if (fmt->tight) { fmt_puts(fmt, "<<"); for (i = 0; i < n; i++) { - fmt_obj(fmt, fz_dict_get_key(obj, i)); + fmt_obj(fmt, pdf_dict_get_key(obj, i)); fmt_sep(fmt); - fmt_obj(fmt, fz_dict_get_val(obj, i)); + fmt_obj(fmt, pdf_dict_get_val(obj, i)); fmt_sep(fmt); } fmt_puts(fmt, ">>"); @@ -1132,16 +1133,16 @@ static void fmt_dict(struct fmt *fmt, fz_obj *obj) fmt_puts(fmt, "<<\n"); fmt->indent ++; for (i = 0; i < n; i++) { - key = fz_dict_get_key(obj, i); - val = fz_dict_get_val(obj, i); + key = pdf_dict_get_key(obj, i); + val = pdf_dict_get_val(obj, i); fmt_indent(fmt); fmt_obj(fmt, key); fmt_putc(fmt, ' '); - if (!fz_is_indirect(val) && fz_is_array(val)) + if (!pdf_is_indirect(val) && pdf_is_array(val)) fmt->indent ++; fmt_obj(fmt, val); fmt_putc(fmt, '\n'); - if (!fz_is_indirect(val) && fz_is_array(val)) + if (!pdf_is_indirect(val) && pdf_is_array(val)) fmt->indent --; } fmt->indent --; @@ -1150,37 +1151,37 @@ static void fmt_dict(struct fmt *fmt, fz_obj *obj) } } -static void fmt_obj(struct fmt *fmt, fz_obj *obj) +static void fmt_obj(struct fmt *fmt, pdf_obj *obj) { char buf[256]; if (!obj) fmt_puts(fmt, "<NULL>"); - else if (fz_is_indirect(obj)) + else if (pdf_is_indirect(obj)) { - sprintf(buf, "%d %d R", fz_to_num(obj), fz_to_gen(obj)); + sprintf(buf, "%d %d R", pdf_to_num(obj), pdf_to_gen(obj)); fmt_puts(fmt, buf); } - else if (fz_is_null(obj)) + else if (pdf_is_null(obj)) fmt_puts(fmt, "null"); - else if (fz_is_bool(obj)) - fmt_puts(fmt, fz_to_bool(obj) ? "true" : "false"); - else if (fz_is_int(obj)) + else if (pdf_is_bool(obj)) + fmt_puts(fmt, pdf_to_bool(obj) ? "true" : "false"); + else if (pdf_is_int(obj)) { - sprintf(buf, "%d", fz_to_int(obj)); + sprintf(buf, "%d", pdf_to_int(obj)); fmt_puts(fmt, buf); } - else if (fz_is_real(obj)) + else if (pdf_is_real(obj)) { - sprintf(buf, "%g", fz_to_real(obj)); + sprintf(buf, "%g", pdf_to_real(obj)); if (strchr(buf, 'e')) /* bad news! */ - sprintf(buf, fabsf(fz_to_real(obj)) > 1 ? "%1.1f" : "%1.8f", fz_to_real(obj)); + sprintf(buf, fabsf(pdf_to_real(obj)) > 1 ? "%1.1f" : "%1.8f", pdf_to_real(obj)); fmt_puts(fmt, buf); } - else if (fz_is_string(obj)) + else if (pdf_is_string(obj)) { - char *str = fz_to_str_buf(obj); - int len = fz_to_str_len(obj); + char *str = pdf_to_str_buf(obj); + int len = pdf_to_str_len(obj); int added = 0; int i, c; for (i = 0; i < len; i++) { @@ -1195,18 +1196,18 @@ static void fmt_obj(struct fmt *fmt, fz_obj *obj) else fmt_hex(fmt, obj); } - else if (fz_is_name(obj)) + else if (pdf_is_name(obj)) fmt_name(fmt, obj); - else if (fz_is_array(obj)) + else if (pdf_is_array(obj)) fmt_array(fmt, obj); - else if (fz_is_dict(obj)) + else if (pdf_is_dict(obj)) fmt_dict(fmt, obj); else fmt_puts(fmt, "<unknown object>"); } static int -fz_sprint_obj(char *s, int n, fz_obj *obj, int tight) +pdf_sprint_obj(char *s, int n, pdf_obj *obj, int tight) { struct fmt fmt; @@ -1228,23 +1229,23 @@ fz_sprint_obj(char *s, int n, fz_obj *obj, int tight) } int -fz_fprint_obj(FILE *fp, fz_obj *obj, int tight) +pdf_fprint_obj(FILE *fp, pdf_obj *obj, int tight) { char buf[1024]; char *ptr; int n; - n = fz_sprint_obj(NULL, 0, obj, tight); + n = pdf_sprint_obj(NULL, 0, obj, tight); if ((n + 1) < sizeof buf) { - fz_sprint_obj(buf, sizeof buf, obj, tight); + pdf_sprint_obj(buf, sizeof buf, obj, tight); fputs(buf, fp); fputc('\n', fp); } else { ptr = fz_malloc(obj->ctx, n + 1); - fz_sprint_obj(ptr, n + 1, obj, tight); + pdf_sprint_obj(ptr, n + 1, obj, tight); fputs(ptr, fp); fputc('\n', fp); fz_free(obj->ctx, ptr); @@ -1253,13 +1254,13 @@ fz_fprint_obj(FILE *fp, fz_obj *obj, int tight) } void -fz_debug_obj(fz_obj *obj) +pdf_print_obj(pdf_obj *obj) { - fz_fprint_obj(stdout, obj, 0); + pdf_fprint_obj(stdout, obj, 0); } void -fz_debug_ref(fz_obj *ref) +pdf_print_ref(pdf_obj *ref) { - fz_debug_obj(fz_resolve_indirect(ref)); + pdf_print_obj(pdf_resolve_indirect(ref)); } diff --git a/pdf/mupdf-internal.h b/pdf/mupdf-internal.h new file mode 100644 index 00000000..3e4a4729 --- /dev/null +++ b/pdf/mupdf-internal.h @@ -0,0 +1,535 @@ +#ifndef MUPDF_INTERNAL_H +#define MUPDF_INTERNAL_H + +#include "mupdf.h" +#include "fitz-internal.h" + +void pdf_set_str_len(pdf_obj *obj, int newlen); +void *pdf_get_indirect_document(pdf_obj *obj); + +/* + * PDF Images + */ + +typedef struct pdf_image_params_s pdf_image_params; + +struct pdf_image_params_s +{ + int type; + fz_colorspace *colorspace; + union + { + struct + { + int columns; + int rows; + int k; + int eol; + int eba; + int eob; + int bi1; + } + fax; + struct + { + int ct; + } + jpeg; + struct + { + int columns; + int colors; + int predictor; + int bpc; + } + flate; + struct + { + int columns; + int colors; + int predictor; + int bpc; + int ec; + } + lzw; + } + u; +}; + + +typedef struct pdf_image_s pdf_image; + +struct pdf_image_s +{ + fz_image base; + fz_pixmap *tile; + int n, bpc; + pdf_image_params params; + fz_buffer *buffer; + int colorkey[FZ_MAX_COLORS * 2]; + float decode[FZ_MAX_COLORS * 2]; + int imagemask; + int interpolate; + int usecolorkey; +}; + +enum +{ + PDF_IMAGE_RAW, + PDF_IMAGE_FAX, + PDF_IMAGE_JPEG, + PDF_IMAGE_RLD, + PDF_IMAGE_FLATE, + PDF_IMAGE_LZW, + PDF_IMAGE_JPX +}; + +/* + * tokenizer and low-level object parser + */ + +enum +{ + PDF_TOK_ERROR, PDF_TOK_EOF, + PDF_TOK_OPEN_ARRAY, PDF_TOK_CLOSE_ARRAY, + PDF_TOK_OPEN_DICT, PDF_TOK_CLOSE_DICT, + PDF_TOK_OPEN_BRACE, PDF_TOK_CLOSE_BRACE, + PDF_TOK_NAME, PDF_TOK_INT, PDF_TOK_REAL, PDF_TOK_STRING, PDF_TOK_KEYWORD, + PDF_TOK_R, PDF_TOK_TRUE, PDF_TOK_FALSE, PDF_TOK_NULL, + PDF_TOK_OBJ, PDF_TOK_ENDOBJ, + PDF_TOK_STREAM, PDF_TOK_ENDSTREAM, + PDF_TOK_XREF, PDF_TOK_TRAILER, PDF_TOK_STARTXREF, + PDF_NUM_TOKENS +}; + +enum +{ + PDF_LEXBUF_SMALL = 256, + PDF_LEXBUF_LARGE = 65536 +}; + +typedef struct pdf_lexbuf_s pdf_lexbuf; +typedef struct pdf_lexbuf_large_s pdf_lexbuf_large; + +struct pdf_lexbuf_s +{ + int size; + int len; + int i; + float f; + char scratch[PDF_LEXBUF_SMALL]; +}; + +struct pdf_lexbuf_large_s +{ + pdf_lexbuf base; + char scratch[PDF_LEXBUF_LARGE - PDF_LEXBUF_SMALL]; +}; + +int pdf_lex(fz_stream *f, pdf_lexbuf *lexbuf); + +pdf_obj *pdf_parse_array(pdf_document *doc, fz_stream *f, pdf_lexbuf *buf); +pdf_obj *pdf_parse_dict(pdf_document *doc, fz_stream *f, pdf_lexbuf *buf); +pdf_obj *pdf_parse_stm_obj(pdf_document *doc, fz_stream *f, pdf_lexbuf *buf); +pdf_obj *pdf_parse_ind_obj(pdf_document *doc, fz_stream *f, pdf_lexbuf *buf, int *num, int *gen, int *stm_ofs); + +/* + * xref and object / stream api + */ + +typedef struct pdf_xref_entry_s pdf_xref_entry; + +struct pdf_xref_entry_s +{ + int ofs; /* file offset / objstm object number */ + int gen; /* generation / objstm index */ + int stm_ofs; /* on-disk stream */ + pdf_obj *obj; /* stored/cached object */ + int type; /* 0=unset (f)ree i(n)use (o)bjstm */ +}; + +typedef struct pdf_crypt_s pdf_crypt; +typedef struct pdf_ocg_descriptor_s pdf_ocg_descriptor; +typedef struct pdf_ocg_entry_s pdf_ocg_entry; + +struct pdf_ocg_entry_s +{ + int num; + int gen; + int state; +}; + +struct pdf_ocg_descriptor_s +{ + int len; + pdf_ocg_entry *ocgs; + pdf_obj *intent; +}; + +struct pdf_document_s +{ + fz_document super; + + fz_context *ctx; + fz_stream *file; + + int version; + int startxref; + int file_size; + pdf_crypt *crypt; + pdf_obj *trailer; + pdf_ocg_descriptor *ocg; + + int len; + pdf_xref_entry *table; + + int page_len; + int page_cap; + pdf_obj **page_objs; + pdf_obj **page_refs; + + pdf_lexbuf_large lexbuf; +}; + +void pdf_cache_object(pdf_document *doc, int num, int gen); + +fz_stream *pdf_open_inline_stream(pdf_document *doc, pdf_obj *stmobj, int length, fz_stream *chain, pdf_image_params *params); +fz_buffer *pdf_load_image_stream(pdf_document *doc, int num, int gen, pdf_image_params *params); +fz_stream *pdf_open_image_stream(pdf_document *doc, int num, int gen, pdf_image_params *params); +fz_stream *pdf_open_stream_with_offset(pdf_document *doc, int num, int gen, pdf_obj *dict, int stm_ofs); +fz_stream *pdf_open_image_decomp_stream(fz_context *ctx, fz_buffer *, pdf_image_params *params, int *factor); + +void pdf_repair_xref(pdf_document *doc, pdf_lexbuf *buf); +void pdf_repair_obj_stms(pdf_document *doc); +void pdf_print_xref(pdf_document *); +void pdf_resize_xref(pdf_document *doc, int newcap); + +/* + * Encryption + */ + +pdf_crypt *pdf_new_crypt(fz_context *ctx, pdf_obj *enc, pdf_obj *id); +void pdf_free_crypt(fz_context *ctx, pdf_crypt *crypt); + +void pdf_crypt_obj(fz_context *ctx, pdf_crypt *crypt, pdf_obj *obj, int num, int gen); +fz_stream *pdf_open_crypt(fz_stream *chain, pdf_crypt *crypt, int num, int gen); +fz_stream *pdf_open_crypt_with_filter(fz_stream *chain, pdf_crypt *crypt, char *name, int num, int gen); + +int pdf_crypt_revision(pdf_document *doc); +char *pdf_crypt_method(pdf_document *doc); +int pdf_crypt_length(pdf_document *doc); +unsigned char *pdf_crypt_key(pdf_document *doc); + +void pdf_print_crypt(pdf_crypt *crypt); + +/* + * Functions, Colorspaces, Shadings and Images + */ + +typedef struct pdf_function_s pdf_function; + +pdf_function *pdf_load_function(pdf_document *doc, pdf_obj *ref); +void pdf_eval_function(fz_context *ctx, pdf_function *func, float *in, int inlen, float *out, int outlen); +pdf_function *pdf_keep_function(fz_context *ctx, pdf_function *func); +void pdf_drop_function(fz_context *ctx, pdf_function *func); +unsigned int pdf_function_size(pdf_function *func); + +fz_colorspace *pdf_load_colorspace(pdf_document *doc, pdf_obj *obj); +fz_pixmap *pdf_expand_indexed_pixmap(fz_context *ctx, fz_pixmap *src); + +fz_shade *pdf_load_shading(pdf_document *doc, pdf_obj *obj); + +fz_image *pdf_load_inline_image(pdf_document *doc, pdf_obj *rdb, pdf_obj *dict, fz_stream *file); +int pdf_is_jpx_image(fz_context *ctx, pdf_obj *dict); + +/* + * Pattern + */ + +typedef struct pdf_pattern_s pdf_pattern; + +struct pdf_pattern_s +{ + fz_storable storable; + int ismask; + float xstep; + float ystep; + fz_matrix matrix; + fz_rect bbox; + pdf_obj *resources; + fz_buffer *contents; +}; + +pdf_pattern *pdf_load_pattern(pdf_document *doc, pdf_obj *obj); +pdf_pattern *pdf_keep_pattern(fz_context *ctx, pdf_pattern *pat); +void pdf_drop_pattern(fz_context *ctx, pdf_pattern *pat); + +/* + * XObject + */ + +typedef struct pdf_xobject_s pdf_xobject; + +struct pdf_xobject_s +{ + fz_storable storable; + fz_matrix matrix; + fz_rect bbox; + int isolated; + int knockout; + int transparency; + fz_colorspace *colorspace; + pdf_obj *resources; + fz_buffer *contents; + pdf_obj *me; +}; + +pdf_xobject *pdf_load_xobject(pdf_document *doc, pdf_obj *obj); +pdf_xobject *pdf_keep_xobject(fz_context *ctx, pdf_xobject *xobj); +void pdf_drop_xobject(fz_context *ctx, pdf_xobject *xobj); + +/* + * CMap + */ + +typedef struct pdf_cmap_s pdf_cmap; +typedef struct pdf_range_s pdf_range; + +enum { PDF_CMAP_SINGLE, PDF_CMAP_RANGE, PDF_CMAP_TABLE, PDF_CMAP_MULTI }; + +struct pdf_range_s +{ + unsigned short low; + /* Next, we pack 2 fields into the same unsigned short. Top 14 bits + * are the extent, bottom 2 bits are flags: single, range, table, + * multi */ + unsigned short extent_flags; + unsigned short offset; /* range-delta or table-index */ +}; + +struct pdf_cmap_s +{ + fz_storable storable; + char cmap_name[32]; + + char usecmap_name[32]; + pdf_cmap *usecmap; + + int wmode; + + int codespace_len; + struct + { + unsigned short n; + unsigned short low; + unsigned short high; + } codespace[40]; + + int rlen, rcap; + pdf_range *ranges; + + int tlen, tcap; + unsigned short *table; +}; + +pdf_cmap *pdf_new_cmap(fz_context *ctx); +pdf_cmap *pdf_keep_cmap(fz_context *ctx, pdf_cmap *cmap); +void pdf_drop_cmap(fz_context *ctx, pdf_cmap *cmap); +void pdf_free_cmap_imp(fz_context *ctx, fz_storable *cmap); +unsigned int pdf_cmap_size(fz_context *ctx, pdf_cmap *cmap); + +void pdf_print_cmap(fz_context *ctx, pdf_cmap *cmap); +int pdf_cmap_wmode(fz_context *ctx, pdf_cmap *cmap); +void pdf_set_cmap_wmode(fz_context *ctx, pdf_cmap *cmap, int wmode); +void pdf_set_usecmap(fz_context *ctx, pdf_cmap *cmap, pdf_cmap *usecmap); + +void pdf_add_codespace(fz_context *ctx, pdf_cmap *cmap, int low, int high, int n); +void pdf_map_range_to_table(fz_context *ctx, pdf_cmap *cmap, int low, int *map, int len); +void pdf_map_range_to_range(fz_context *ctx, pdf_cmap *cmap, int srclo, int srchi, int dstlo); +void pdf_map_one_to_many(fz_context *ctx, pdf_cmap *cmap, int one, int *many, int len); +void pdf_sort_cmap(fz_context *ctx, pdf_cmap *cmap); + +int pdf_lookup_cmap(pdf_cmap *cmap, int cpt); +int pdf_lookup_cmap_full(pdf_cmap *cmap, int cpt, int *out); +int pdf_decode_cmap(pdf_cmap *cmap, unsigned char *s, int *cpt); + +pdf_cmap *pdf_new_identity_cmap(fz_context *ctx, int wmode, int bytes); +pdf_cmap *pdf_load_cmap(fz_context *ctx, fz_stream *file); +pdf_cmap *pdf_load_system_cmap(fz_context *ctx, char *name); +pdf_cmap *pdf_load_builtin_cmap(fz_context *ctx, char *name); +pdf_cmap *pdf_load_embedded_cmap(pdf_document *doc, pdf_obj *ref); + +/* + * Font + */ + +enum +{ + PDF_FD_FIXED_PITCH = 1 << 0, + PDF_FD_SERIF = 1 << 1, + PDF_FD_SYMBOLIC = 1 << 2, + PDF_FD_SCRIPT = 1 << 3, + PDF_FD_NONSYMBOLIC = 1 << 5, + PDF_FD_ITALIC = 1 << 6, + PDF_FD_ALL_CAP = 1 << 16, + PDF_FD_SMALL_CAP = 1 << 17, + PDF_FD_FORCE_BOLD = 1 << 18 +}; + +enum { PDF_ROS_CNS, PDF_ROS_GB, PDF_ROS_JAPAN, PDF_ROS_KOREA }; + +void pdf_load_encoding(char **estrings, char *encoding); +int pdf_lookup_agl(char *name); +const char **pdf_lookup_agl_duplicates(int ucs); + +extern const unsigned short pdf_doc_encoding[256]; +extern const char * const pdf_mac_roman[256]; +extern const char * const pdf_mac_expert[256]; +extern const char * const pdf_win_ansi[256]; +extern const char * const pdf_standard[256]; + +typedef struct pdf_font_desc_s pdf_font_desc; +typedef struct pdf_hmtx_s pdf_hmtx; +typedef struct pdf_vmtx_s pdf_vmtx; + +struct pdf_hmtx_s +{ + unsigned short lo; + unsigned short hi; + int w; /* type3 fonts can be big! */ +}; + +struct pdf_vmtx_s +{ + unsigned short lo; + unsigned short hi; + short x; + short y; + short w; +}; + +struct pdf_font_desc_s +{ + fz_storable storable; + unsigned int size; + + fz_font *font; + + /* FontDescriptor */ + int flags; + float italic_angle; + float ascent; + float descent; + float cap_height; + float x_height; + float missing_width; + + /* Encoding (CMap) */ + pdf_cmap *encoding; + pdf_cmap *to_ttf_cmap; + int cid_to_gid_len; + unsigned short *cid_to_gid; + + /* ToUnicode */ + pdf_cmap *to_unicode; + int cid_to_ucs_len; + unsigned short *cid_to_ucs; + + /* Metrics (given in the PDF file) */ + int wmode; + + int hmtx_len, hmtx_cap; + pdf_hmtx dhmtx; + pdf_hmtx *hmtx; + + int vmtx_len, vmtx_cap; + pdf_vmtx dvmtx; + pdf_vmtx *vmtx; + + int is_embedded; +}; + +void pdf_set_font_wmode(fz_context *ctx, pdf_font_desc *font, int wmode); +void pdf_set_default_hmtx(fz_context *ctx, pdf_font_desc *font, int w); +void pdf_set_default_vmtx(fz_context *ctx, pdf_font_desc *font, int y, int w); +void pdf_add_hmtx(fz_context *ctx, pdf_font_desc *font, int lo, int hi, int w); +void pdf_add_vmtx(fz_context *ctx, pdf_font_desc *font, int lo, int hi, int x, int y, int w); +void pdf_end_hmtx(fz_context *ctx, pdf_font_desc *font); +void pdf_end_vmtx(fz_context *ctx, pdf_font_desc *font); +pdf_hmtx pdf_lookup_hmtx(fz_context *ctx, pdf_font_desc *font, int cid); +pdf_vmtx pdf_lookup_vmtx(fz_context *ctx, pdf_font_desc *font, int cid); + +void pdf_load_to_unicode(pdf_document *doc, pdf_font_desc *font, char **strings, char *collection, pdf_obj *cmapstm); + +int pdf_font_cid_to_gid(fz_context *ctx, pdf_font_desc *fontdesc, int cid); + +unsigned char *pdf_lookup_builtin_font(char *name, unsigned int *len); +unsigned char *pdf_lookup_substitute_font(int mono, int serif, int bold, int italic, unsigned int *len); +unsigned char *pdf_lookup_substitute_cjk_font(int ros, int serif, unsigned int *len); + +pdf_font_desc *pdf_load_type3_font(pdf_document *doc, pdf_obj *rdb, pdf_obj *obj); +pdf_font_desc *pdf_load_font(pdf_document *doc, pdf_obj *rdb, pdf_obj *obj); + +pdf_font_desc *pdf_new_font_desc(fz_context *ctx); +pdf_font_desc *pdf_keep_font(fz_context *ctx, pdf_font_desc *fontdesc); +void pdf_drop_font(fz_context *ctx, pdf_font_desc *font); + +void pdf_print_font(fz_context *ctx, pdf_font_desc *fontdesc); + +/* + * Interactive features + */ + +typedef struct pdf_annot_s pdf_annot; + +struct pdf_annot_s +{ + pdf_obj *obj; + fz_rect rect; + pdf_xobject *ap; + fz_matrix matrix; + pdf_annot *next; +}; + +fz_link_dest pdf_parse_link_dest(pdf_document *doc, pdf_obj *dest); +fz_link_dest pdf_parse_action(pdf_document *doc, pdf_obj *action); +pdf_obj *pdf_lookup_dest(pdf_document *doc, pdf_obj *needle); +pdf_obj *pdf_lookup_name(pdf_document *doc, char *which, pdf_obj *needle); +pdf_obj *pdf_load_name_tree(pdf_document *doc, char *which); + +fz_link *pdf_load_link_annots(pdf_document *, pdf_obj *annots, fz_matrix page_ctm); + +pdf_annot *pdf_load_annots(pdf_document *, pdf_obj *annots); +void pdf_free_annot(fz_context *ctx, pdf_annot *link); + +/* + * Page tree, pages and related objects + */ + +struct pdf_page_s +{ + fz_matrix ctm; /* calculated from mediabox and rotate */ + fz_rect mediabox; + int rotate; + int transparency; + pdf_obj *resources; + fz_buffer *contents; + fz_link *links; + pdf_annot *annots; +}; + +/* + * Content stream parsing + */ + +void pdf_run_glyph(pdf_document *doc, pdf_obj *resources, fz_buffer *contents, fz_device *dev, fz_matrix ctm, void *gstate); + +/* + * PDF interface to store + */ + +void pdf_store_item(fz_context *ctx, pdf_obj *key, void *val, unsigned int itemsize); +void *pdf_find_item(fz_context *ctx, fz_store_free_fn *free, pdf_obj *key); +void pdf_remove_item(fz_context *ctx, fz_store_free_fn *free, pdf_obj *key); + +#endif diff --git a/pdf/mupdf.h b/pdf/mupdf.h index 39245177..b88f7423 100644 --- a/pdf/mupdf.h +++ b/pdf/mupdf.h @@ -1,127 +1,151 @@ -#ifndef _MUPDF_H_ -#define _MUPDF_H_ +#ifndef MUPDF_H +#define MUPDF_H -#ifndef _FITZ_H_ -#error "fitz.h must be included before mupdf.h" -#endif +#include "fitz.h" typedef struct pdf_document_s pdf_document; /* - * tokenizer and low-level object parser + * Dynamic objects. + * The same type of objects as found in PDF and PostScript. + * Used by the filters and the mupdf parser. */ -enum -{ - PDF_TOK_ERROR, PDF_TOK_EOF, - PDF_TOK_OPEN_ARRAY, PDF_TOK_CLOSE_ARRAY, - PDF_TOK_OPEN_DICT, PDF_TOK_CLOSE_DICT, - PDF_TOK_OPEN_BRACE, PDF_TOK_CLOSE_BRACE, - PDF_TOK_NAME, PDF_TOK_INT, PDF_TOK_REAL, PDF_TOK_STRING, PDF_TOK_KEYWORD, - PDF_TOK_R, PDF_TOK_TRUE, PDF_TOK_FALSE, PDF_TOK_NULL, - PDF_TOK_OBJ, PDF_TOK_ENDOBJ, - PDF_TOK_STREAM, PDF_TOK_ENDSTREAM, - PDF_TOK_XREF, PDF_TOK_TRAILER, PDF_TOK_STARTXREF, - PDF_NUM_TOKENS -}; - -int pdf_lex(fz_stream *f, char *buf, int n, int *len); - -fz_obj *pdf_parse_array(pdf_document *doc, fz_stream *f, char *buf, int cap); -fz_obj *pdf_parse_dict(pdf_document *doc, fz_stream *f, char *buf, int cap); -fz_obj *pdf_parse_stm_obj(pdf_document *doc, fz_stream *f, char *buf, int cap); -fz_obj *pdf_parse_ind_obj(pdf_document *doc, fz_stream *f, char *buf, int cap, int *num, int *gen, int *stm_ofs); +typedef struct pdf_obj_s pdf_obj; + +pdf_obj *pdf_new_null(fz_context *ctx); +pdf_obj *pdf_new_bool(fz_context *ctx, int b); +pdf_obj *pdf_new_int(fz_context *ctx, int i); +pdf_obj *pdf_new_real(fz_context *ctx, float f); +pdf_obj *fz_new_name(fz_context *ctx, char *str); +pdf_obj *pdf_new_string(fz_context *ctx, char *str, int len); +pdf_obj *pdf_new_indirect(fz_context *ctx, int num, int gen, void *doc); + +pdf_obj *pdf_new_array(fz_context *ctx, int initialcap); +pdf_obj *pdf_new_dict(fz_context *ctx, int initialcap); +pdf_obj *pdf_copy_array(fz_context *ctx, pdf_obj *array); +pdf_obj *pdf_copy_dict(fz_context *ctx, pdf_obj *dict); + +pdf_obj *pdf_keep_obj(pdf_obj *obj); +void pdf_drop_obj(pdf_obj *obj); + +/* type queries */ +int pdf_is_null(pdf_obj *obj); +int pdf_is_bool(pdf_obj *obj); +int pdf_is_int(pdf_obj *obj); +int pdf_is_real(pdf_obj *obj); +int pdf_is_name(pdf_obj *obj); +int pdf_is_string(pdf_obj *obj); +int pdf_is_array(pdf_obj *obj); +int pdf_is_dict(pdf_obj *obj); +int pdf_is_indirect(pdf_obj *obj); +int pdf_is_stream(pdf_document *doc, int num, int gen); -fz_rect pdf_to_rect(fz_context *ctx, fz_obj *array); -fz_matrix pdf_to_matrix(fz_context *ctx, fz_obj *array); -char *pdf_to_utf8(fz_context *ctx, fz_obj *src); -unsigned short *pdf_to_ucs2(fz_context *ctx, fz_obj *src); -fz_obj *pdf_to_utf8_name(fz_context *ctx, fz_obj *src); +int pdf_objcmp(pdf_obj *a, pdf_obj *b); + +/* dict marking and unmarking functions - to avoid infinite recursions */ +int pdf_dict_marked(pdf_obj *obj); +int pdf_dict_mark(pdf_obj *obj); +void pdf_dict_unmark(pdf_obj *obj); + +/* safe, silent failure, no error reporting on type mismatches */ +int pdf_to_bool(pdf_obj *obj); +int pdf_to_int(pdf_obj *obj); +float pdf_to_real(pdf_obj *obj); +char *pdf_to_name(pdf_obj *obj); +char *pdf_to_str_buf(pdf_obj *obj); +pdf_obj *pdf_to_dict(pdf_obj *obj); +int pdf_to_str_len(pdf_obj *obj); +int pdf_to_num(pdf_obj *obj); +int pdf_to_gen(pdf_obj *obj); + +int pdf_array_len(pdf_obj *array); +pdf_obj *pdf_array_get(pdf_obj *array, int i); +void pdf_array_put(pdf_obj *array, int i, pdf_obj *obj); +void pdf_array_push(pdf_obj *array, pdf_obj *obj); +void pdf_array_insert(pdf_obj *array, pdf_obj *obj); +int pdf_array_contains(pdf_obj *array, pdf_obj *obj); + +int pdf_dict_len(pdf_obj *dict); +pdf_obj *pdf_dict_get_key(pdf_obj *dict, int idx); +pdf_obj *pdf_dict_get_val(pdf_obj *dict, int idx); +pdf_obj *pdf_dict_get(pdf_obj *dict, pdf_obj *key); +pdf_obj *pdf_dict_gets(pdf_obj *dict, char *key); +pdf_obj *pdf_dict_getsa(pdf_obj *dict, char *key, char *abbrev); +void fz_dict_put(pdf_obj *dict, pdf_obj *key, pdf_obj *val); +void pdf_dict_puts(pdf_obj *dict, char *key, pdf_obj *val); +void pdf_dict_del(pdf_obj *dict, pdf_obj *key); +void pdf_dict_dels(pdf_obj *dict, char *key); +void pdf_sort_dict(pdf_obj *dict); + +int pdf_fprint_obj(FILE *fp, pdf_obj *obj, int tight); +void pdf_print_obj(pdf_obj *obj); +void pdf_print_ref(pdf_obj *obj); + +char *pdf_to_utf8(fz_context *ctx, pdf_obj *src); +unsigned short *pdf_to_ucs2(fz_context *ctx, pdf_obj *src); /* sumatrapdf */ +pdf_obj *pdf_to_utf8_name(fz_context *ctx, pdf_obj *src); char *pdf_from_ucs2(fz_context *ctx, unsigned short *str); -/* - * xref and object / stream api - */ - -typedef struct pdf_xref_entry_s pdf_xref_entry; -typedef struct pdf_crypt_s pdf_crypt; -typedef struct pdf_ocg_descriptor_s pdf_ocg_descriptor; -typedef struct pdf_ocg_entry_s pdf_ocg_entry; - -struct pdf_xref_entry_s -{ - int ofs; /* file offset / objstm object number */ - int gen; /* generation / objstm index */ - int stm_ofs; /* on-disk stream */ - fz_obj *obj; /* stored/cached object */ - int type; /* 0=unset (f)ree i(n)use (o)bjstm */ -}; - -struct pdf_ocg_entry_s -{ - int num; - int gen; - int state; -}; - -struct pdf_ocg_descriptor_s -{ - int len; - pdf_ocg_entry *ocgs; - fz_obj *intent; -}; - -struct pdf_document_s -{ - fz_document super; - - fz_context *ctx; - fz_stream *file; +fz_rect pdf_to_rect(fz_context *ctx, pdf_obj *array); +fz_matrix pdf_to_matrix(fz_context *ctx, pdf_obj *array); - int version; - int startxref; - int file_size; - pdf_crypt *crypt; - fz_obj *trailer; - pdf_ocg_descriptor *ocg; - - int len; - pdf_xref_entry *table; - - int page_len; - int page_cap; - fz_obj **page_objs; - fz_obj **page_refs; - - char scratch[65536]; -}; +int pdf_count_objects(pdf_document *doc); +pdf_obj *pdf_resolve_indirect(pdf_obj *ref); +pdf_obj *pdf_load_object(pdf_document *doc, int num, int gen); +void pdf_update_object(pdf_document *doc, int num, int gen, pdf_obj *newobj); -fz_obj *pdf_resolve_indirect(fz_obj *ref); -void pdf_cache_object(pdf_document *doc, int num, int gen); -fz_obj *pdf_load_object(pdf_document *doc, int num, int gen); -void pdf_update_object(pdf_document *doc, int num, int gen, fz_obj *newobj); - -int pdf_is_stream(pdf_document *doc, int num, int gen); -fz_stream *pdf_open_inline_stream(pdf_document *doc, fz_obj *stmobj, int length, fz_stream *chain); fz_buffer *pdf_load_raw_stream(pdf_document *doc, int num, int gen); fz_buffer *pdf_load_stream(pdf_document *doc, int num, int gen); fz_stream *pdf_open_raw_stream(pdf_document *doc, int num, int gen); fz_stream *pdf_open_stream(pdf_document *doc, int num, int gen); -fz_stream *pdf_open_stream_with_offset(pdf_document *doc, int num, int gen, fz_obj *dict, int stm_ofs); -pdf_document *pdf_open_document_with_stream(fz_stream *file); +fz_image *pdf_load_image(pdf_document *doc, pdf_obj *obj); + +fz_outline *pdf_load_outline(pdf_document *doc); + +/* + pdf_open_document: Open a PDF document. + + Open a PDF document by reading its cross reference table, so + MuPDF can locate PDF objects inside the file. Upon an broken + cross reference table or other parse errors MuPDF will restart + parsing the file from the beginning to try to rebuild a + (hopefully correct) cross reference table to allow further + processing of the file. + + The returned pdf_document should be used when calling most + other PDF functions. Note that it wraps the context, so those + functions implicitly get access to the global state in + context. + + filename: a path to a file as it would be given to open(2). +*/ pdf_document *pdf_open_document(fz_context *ctx, const char *filename); -void pdf_close_document(pdf_document *doc); -/* private */ -void pdf_repair_xref(pdf_document *doc, char *buf, int bufsize); -void pdf_repair_obj_stms(pdf_document *doc); -void pdf_debug_xref(pdf_document *); -void pdf_resize_xref(pdf_document *doc, int newcap); +/* + pdf_open_document_with_stream: Opens a PDF document. + + Same as pdf_open_document, but takes a stream instead of a + filename to locate the PDF document to open. Increments the + reference count of the stream. See fz_open_file, + fz_open_file_w or fz_open_fd for opening a stream, and + fz_close for closing an open stream. +*/ +pdf_document *pdf_open_document_with_stream(fz_stream *file); /* - * Encryption - */ + pdf_close_document: Closes and frees an opened PDF document. + + The resource store in the context associated with pdf_document + is emptied. + + Does not throw exceptions. +*/ +void pdf_close_document(pdf_document *doc); + +int pdf_needs_password(pdf_document *doc); +int pdf_authenticate_password(pdf_document *doc, char *pw); enum { @@ -136,339 +160,58 @@ enum PDF_DEFAULT_PERM_FLAGS = 0xfffc }; -pdf_crypt *pdf_new_crypt(fz_context *ctx, fz_obj *enc, fz_obj *id); -void pdf_free_crypt(fz_context *ctx, pdf_crypt *crypt); - -void pdf_crypt_obj(fz_context *ctx, pdf_crypt *crypt, fz_obj *obj, int num, int gen); -fz_stream *pdf_open_crypt(fz_stream *chain, pdf_crypt *crypt, int num, int gen); -fz_stream *pdf_open_crypt_with_filter(fz_stream *chain, pdf_crypt *crypt, char *name, int num, int gen); - -int pdf_needs_password(pdf_document *doc); -int pdf_authenticate_password(pdf_document *doc, char *pw); int pdf_has_permission(pdf_document *doc, int p); -int pdf_get_crypt_revision(pdf_document *doc); -char *pdf_get_crypt_method(pdf_document *doc); -int pdf_get_crypt_length(pdf_document *doc); -unsigned char *pdf_get_crypt_key(pdf_document *doc); - -void pdf_debug_crypt(pdf_crypt *crypt); - -/* - * Functions, Colorspaces, Shadings and Images - */ - -typedef struct pdf_function_s pdf_function; - -pdf_function *pdf_load_function(pdf_document *doc, fz_obj *ref); -void pdf_eval_function(fz_context *ctx, pdf_function *func, float *in, int inlen, float *out, int outlen); -pdf_function *pdf_keep_function(fz_context *ctx, pdf_function *func); -void pdf_drop_function(fz_context *ctx, pdf_function *func); -unsigned int pdf_function_size(pdf_function *func); - -fz_colorspace *pdf_load_colorspace(pdf_document *doc, fz_obj *obj); -fz_pixmap *pdf_expand_indexed_pixmap(fz_context *ctx, fz_pixmap *src); - -fz_shade *pdf_load_shading(pdf_document *doc, fz_obj *obj); - -fz_pixmap *pdf_load_inline_image(pdf_document *doc, fz_obj *rdb, fz_obj *dict, fz_stream *file); -fz_pixmap *pdf_load_image(pdf_document *doc, fz_obj *obj); -int pdf_is_jpx_image(fz_context *ctx, fz_obj *dict); - -/* - * Pattern - */ - -typedef struct pdf_pattern_s pdf_pattern; - -struct pdf_pattern_s -{ - fz_storable storable; - int ismask; - float xstep; - float ystep; - fz_matrix matrix; - fz_rect bbox; - fz_obj *resources; - fz_buffer *contents; -}; - -pdf_pattern *pdf_load_pattern(pdf_document *doc, fz_obj *obj); -pdf_pattern *pdf_keep_pattern(fz_context *ctx, pdf_pattern *pat); -void pdf_drop_pattern(fz_context *ctx, pdf_pattern *pat); - -/* - * XObject - */ - -typedef struct pdf_xobject_s pdf_xobject; - -struct pdf_xobject_s -{ - fz_storable storable; - fz_matrix matrix; - fz_rect bbox; - int isolated; - int knockout; - int transparency; - fz_colorspace *colorspace; - fz_obj *resources; - fz_buffer *contents; - fz_obj *me; -}; +typedef struct pdf_page_s pdf_page; -pdf_xobject *pdf_load_xobject(pdf_document *doc, fz_obj *obj); -pdf_xobject *pdf_keep_xobject(fz_context *ctx, pdf_xobject *xobj); -void pdf_drop_xobject(fz_context *ctx, pdf_xobject *xobj); +int pdf_lookup_page_number(pdf_document *doc, pdf_obj *pageobj); +int pdf_count_pages(pdf_document *doc); /* - * CMap - */ - -typedef struct pdf_cmap_s pdf_cmap; -typedef struct pdf_range_s pdf_range; + pdf_load_page: Load a page and its resources. -enum { PDF_CMAP_SINGLE, PDF_CMAP_RANGE, PDF_CMAP_TABLE, PDF_CMAP_MULTI }; + Locates the page in the PDF document and loads the page and its + resources. After pdf_load_page is it possible to retrieve the size + of the page using pdf_bound_page, or to render the page using + pdf_run_page_*. -struct pdf_range_s -{ - unsigned short low; - /* Next, we pack 2 fields into the same unsigned short. Top 14 bits - * are the extent, bottom 2 bits are flags: single, range, table, - * multi */ - unsigned short extent_flags; - unsigned short offset; /* range-delta or table-index */ -}; - -struct pdf_cmap_s -{ - fz_storable storable; - char cmap_name[32]; - - char usecmap_name[32]; - pdf_cmap *usecmap; - - int wmode; - - int codespace_len; - struct - { - unsigned short n; - unsigned short low; - unsigned short high; - } codespace[40]; - - int rlen, rcap; - pdf_range *ranges; - - int tlen, tcap; - unsigned short *table; -}; + number: page number, where 0 is the first page of the document. +*/ +pdf_page *pdf_load_page(pdf_document *doc, int number); -pdf_cmap *pdf_new_cmap(fz_context *ctx); -pdf_cmap *pdf_keep_cmap(fz_context *ctx, pdf_cmap *cmap); -void pdf_drop_cmap(fz_context *ctx, pdf_cmap *cmap); -void pdf_free_cmap_imp(fz_context *ctx, fz_storable *cmap); -unsigned int pdf_cmap_size(fz_context *ctx, pdf_cmap *cmap); - -void pdf_debug_cmap(fz_context *ctx, pdf_cmap *cmap); -int pdf_get_wmode(fz_context *ctx, pdf_cmap *cmap); -void pdf_set_wmode(fz_context *ctx, pdf_cmap *cmap, int wmode); -void pdf_set_usecmap(fz_context *ctx, pdf_cmap *cmap, pdf_cmap *usecmap); - -void pdf_add_codespace(fz_context *ctx, pdf_cmap *cmap, int low, int high, int n); -void pdf_map_range_to_table(fz_context *ctx, pdf_cmap *cmap, int low, int *map, int len); -void pdf_map_range_to_range(fz_context *ctx, pdf_cmap *cmap, int srclo, int srchi, int dstlo); -void pdf_map_one_to_many(fz_context *ctx, pdf_cmap *cmap, int one, int *many, int len); -void pdf_sort_cmap(fz_context *ctx, pdf_cmap *cmap); - -int pdf_lookup_cmap(pdf_cmap *cmap, int cpt); -int pdf_lookup_cmap_full(pdf_cmap *cmap, int cpt, int *out); -int pdf_decode_cmap(pdf_cmap *cmap, unsigned char *s, int *cpt); - -pdf_cmap *pdf_new_identity_cmap(fz_context *ctx, int wmode, int bytes); -pdf_cmap *pdf_load_cmap(fz_context *ctx, fz_stream *file); -pdf_cmap *pdf_load_system_cmap(fz_context *ctx, char *name); -pdf_cmap *pdf_load_builtin_cmap(fz_context *ctx, char *name); -pdf_cmap *pdf_load_embedded_cmap(pdf_document *doc, fz_obj *ref); +fz_link *pdf_load_links(pdf_document *doc, pdf_page *page); /* - * Font - */ - -enum -{ - PDF_FD_FIXED_PITCH = 1 << 0, - PDF_FD_SERIF = 1 << 1, - PDF_FD_SYMBOLIC = 1 << 2, - PDF_FD_SCRIPT = 1 << 3, - PDF_FD_NONSYMBOLIC = 1 << 5, - PDF_FD_ITALIC = 1 << 6, - PDF_FD_ALL_CAP = 1 << 16, - PDF_FD_SMALL_CAP = 1 << 17, - PDF_FD_FORCE_BOLD = 1 << 18 -}; - -enum { PDF_ROS_CNS, PDF_ROS_GB, PDF_ROS_JAPAN, PDF_ROS_KOREA }; - -void pdf_load_encoding(char **estrings, char *encoding); -int pdf_lookup_agl(char *name); -const char **pdf_lookup_agl_duplicates(int ucs); - -extern const unsigned short pdf_doc_encoding[256]; -extern const char * const pdf_mac_roman[256]; -extern const char * const pdf_mac_expert[256]; -extern const char * const pdf_win_ansi[256]; -extern const char * const pdf_standard[256]; - -typedef struct pdf_font_desc_s pdf_font_desc; -typedef struct pdf_hmtx_s pdf_hmtx; -typedef struct pdf_vmtx_s pdf_vmtx; - -struct pdf_hmtx_s -{ - unsigned short lo; - unsigned short hi; - int w; /* type3 fonts can be big! */ -}; - -struct pdf_vmtx_s -{ - unsigned short lo; - unsigned short hi; - short x; - short y; - short w; -}; + pdf_bound_page: Determine the size of a page. -struct pdf_font_desc_s -{ - fz_storable storable; - unsigned int size; - - fz_font *font; - - /* FontDescriptor */ - int flags; - float italic_angle; - float ascent; - float descent; - float cap_height; - float x_height; - float missing_width; - - /* Encoding (CMap) */ - pdf_cmap *encoding; - pdf_cmap *to_ttf_cmap; - int cid_to_gid_len; - unsigned short *cid_to_gid; - - /* ToUnicode */ - pdf_cmap *to_unicode; - int cid_to_ucs_len; - unsigned short *cid_to_ucs; - - /* Metrics (given in the PDF file) */ - int wmode; - - int hmtx_len, hmtx_cap; - pdf_hmtx dhmtx; - pdf_hmtx *hmtx; - - int vmtx_len, vmtx_cap; - pdf_vmtx dvmtx; - pdf_vmtx *vmtx; - - int is_embedded; -}; - -void pdf_set_font_wmode(fz_context *ctx, pdf_font_desc *font, int wmode); -void pdf_set_default_hmtx(fz_context *ctx, pdf_font_desc *font, int w); -void pdf_set_default_vmtx(fz_context *ctx, pdf_font_desc *font, int y, int w); -void pdf_add_hmtx(fz_context *ctx, pdf_font_desc *font, int lo, int hi, int w); -void pdf_add_vmtx(fz_context *ctx, pdf_font_desc *font, int lo, int hi, int x, int y, int w); -void pdf_end_hmtx(fz_context *ctx, pdf_font_desc *font); -void pdf_end_vmtx(fz_context *ctx, pdf_font_desc *font); -pdf_hmtx pdf_get_hmtx(fz_context *ctx, pdf_font_desc *font, int cid); -pdf_vmtx pdf_get_vmtx(fz_context *ctx, pdf_font_desc *font, int cid); - -void pdf_load_to_unicode(pdf_document *doc, pdf_font_desc *font, char **strings, char *collection, fz_obj *cmapstm); - -int pdf_font_cid_to_gid(fz_context *ctx, pdf_font_desc *fontdesc, int cid); + Determine the page size in user space units, taking page rotation + into account. The page size is taken to be the crop box if it + exists (visible area after cropping), otherwise the media box will + be used (possibly including printing marks). -unsigned char *pdf_find_builtin_font(char *name, unsigned int *len); -unsigned char *pdf_find_substitute_font(int mono, int serif, int bold, int italic, unsigned int *len); -unsigned char *pdf_find_substitute_cjk_font(int ros, int serif, unsigned int *len); - -pdf_font_desc *pdf_load_type3_font(pdf_document *doc, fz_obj *rdb, fz_obj *obj); -pdf_font_desc *pdf_load_font(pdf_document *doc, fz_obj *rdb, fz_obj *obj); - -pdf_font_desc *pdf_new_font_desc(fz_context *ctx); -pdf_font_desc *pdf_keep_font(fz_context *ctx, pdf_font_desc *fontdesc); -void pdf_drop_font(fz_context *ctx, pdf_font_desc *font); - -void pdf_debug_font(fz_context *ctx, pdf_font_desc *fontdesc); + Does not throw exceptions. +*/ +fz_rect pdf_bound_page(pdf_document *doc, pdf_page *page); /* - * Interactive features - */ - -typedef struct pdf_annot_s pdf_annot; - -struct pdf_annot_s -{ - fz_obj *obj; - fz_rect rect; - pdf_xobject *ap; - fz_matrix matrix; - pdf_annot *next; -}; - -fz_link_dest pdf_parse_link_dest(pdf_document *doc, fz_obj *dest); -fz_link_dest pdf_parse_action(pdf_document *doc, fz_obj *action); -fz_obj *pdf_lookup_dest(pdf_document *doc, fz_obj *needle); -fz_obj *pdf_lookup_name(pdf_document *doc, char *which, fz_obj *needle); -fz_obj *pdf_load_name_tree(pdf_document *doc, char *which); - -fz_outline *pdf_load_outline(pdf_document *doc); + pdf_free_page: Frees a page and its resources. -fz_link *pdf_load_link_annots(pdf_document *, fz_obj *annots, fz_matrix page_ctm); - -pdf_annot *pdf_load_annots(pdf_document *, fz_obj *annots); -void pdf_free_annot(fz_context *ctx, pdf_annot *link); + Does not throw exceptions. +*/ +void pdf_free_page(pdf_document *doc, pdf_page *page); /* - * Page tree, pages and related objects - */ + pdf_run_page: Interpret a loaded page and render it on a device. -typedef struct pdf_page_s pdf_page; + page: A page loaded by pdf_load_page. -struct pdf_page_s -{ - fz_matrix ctm; /* calculated from mediabox and rotate */ - fz_rect mediabox; - int rotate; - int transparency; - fz_obj *resources; - fz_buffer *contents; - fz_link *links; - pdf_annot *annots; -}; - -int pdf_find_page_number(pdf_document *doc, fz_obj *pageobj); -int pdf_count_pages(pdf_document *doc); + dev: Device used for rendering, obtained from fz_new_*_device. -pdf_page *pdf_load_page(pdf_document *doc, int number); -fz_link *pdf_load_links(pdf_document *doc, pdf_page *page); -fz_rect pdf_bound_page(pdf_document *doc, pdf_page *page); -void pdf_free_page(pdf_document *doc, pdf_page *page); - -/* - * Content stream parsing - */ + ctm: A transformation matrix applied to the objects on the page, + e.g. to scale or rotate the page contents as desired. +*/ +void pdf_run_page(pdf_document *doc, pdf_page *page, fz_device *dev, fz_matrix ctm, fz_cookie *cookie); void pdf_run_page_with_usage(pdf_document *doc, pdf_page *page, fz_device *dev, fz_matrix ctm, char *event, fz_cookie *cookie); -void pdf_run_page(pdf_document *doc, pdf_page *page, fz_device *dev, fz_matrix ctm, fz_cookie *cookie); -void pdf_run_glyph(pdf_document *doc, fz_obj *resources, fz_buffer *contents, fz_device *dev, fz_matrix ctm, void *gstate); #endif diff --git a/pdf/pdf_annot.c b/pdf/pdf_annot.c index ae03f2b6..28300c9b 100644 --- a/pdf/pdf_annot.c +++ b/pdf/pdf_annot.c @@ -1,46 +1,46 @@ -#include "fitz.h" -#include "mupdf.h" +#include "fitz-internal.h" +#include "mupdf-internal.h" -static fz_obj * -resolve_dest_rec(pdf_document *xref, fz_obj *dest, int depth) +static pdf_obj * +resolve_dest_rec(pdf_document *xref, pdf_obj *dest, int depth) { if (depth > 10) /* Arbitrary to avoid infinite recursion */ return NULL; - if (fz_is_name(dest) || fz_is_string(dest)) + if (pdf_is_name(dest) || pdf_is_string(dest)) { dest = pdf_lookup_dest(xref, dest); return resolve_dest_rec(xref, dest, depth+1); } - else if (fz_is_array(dest)) + else if (pdf_is_array(dest)) { return dest; } - else if (fz_is_dict(dest)) + else if (pdf_is_dict(dest)) { - dest = fz_dict_gets(dest, "D"); + dest = pdf_dict_gets(dest, "D"); return resolve_dest_rec(xref, dest, depth+1); } - else if (fz_is_indirect(dest)) + else if (pdf_is_indirect(dest)) return dest; return NULL; } -static fz_obj * -resolve_dest(pdf_document *xref, fz_obj *dest) +static pdf_obj * +resolve_dest(pdf_document *xref, pdf_obj *dest) { return resolve_dest_rec(xref, dest, 0); } fz_link_dest -pdf_parse_link_dest(pdf_document *xref, fz_obj *dest) +pdf_parse_link_dest(pdf_document *xref, pdf_obj *dest) { fz_link_dest ld; - fz_obj *obj; + pdf_obj *obj; int l_from_2 = 0; int b_from_3 = 0; @@ -51,16 +51,16 @@ pdf_parse_link_dest(pdf_document *xref, fz_obj *dest) int z_from_4 = 0; dest = resolve_dest(xref, dest); - if (dest == NULL || !fz_is_array(dest)) + if (dest == NULL || !pdf_is_array(dest)) { ld.kind = FZ_LINK_NONE; return ld; } - obj = fz_array_get(dest, 0); - if (fz_is_int(obj)) - ld.ld.gotor.page = fz_to_int(obj); + obj = pdf_array_get(dest, 0); + if (pdf_is_int(obj)) + ld.ld.gotor.page = pdf_to_int(obj); else - ld.ld.gotor.page = pdf_find_page_number(xref, obj); + ld.ld.gotor.page = pdf_lookup_page_number(xref, obj); ld.kind = FZ_LINK_GOTO; ld.ld.gotor.flags = 0; @@ -71,31 +71,31 @@ pdf_parse_link_dest(pdf_document *xref, fz_obj *dest) ld.ld.gotor.file_spec = NULL; ld.ld.gotor.new_window = 0; - obj = fz_array_get(dest, 1); - if (!fz_is_name(obj)) + obj = pdf_array_get(dest, 1); + if (!pdf_is_name(obj)) return ld; - if (!strcmp("XYZ", fz_to_name(obj))) + if (!strcmp("XYZ", pdf_to_name(obj))) { l_from_2 = t_from_3 = z_from_4 = 1; ld.ld.gotor.flags |= fz_link_flag_r_is_zoom; } - else if ((!strcmp("Fit", fz_to_name(obj))) || (!strcmp("FitB", fz_to_name(obj)))) + else if ((!strcmp("Fit", pdf_to_name(obj))) || (!strcmp("FitB", pdf_to_name(obj)))) { ld.ld.gotor.flags |= fz_link_flag_fit_h; ld.ld.gotor.flags |= fz_link_flag_fit_v; } - else if ((!strcmp("FitH", fz_to_name(obj))) || (!strcmp("FitBH", fz_to_name(obj)))) + else if ((!strcmp("FitH", pdf_to_name(obj))) || (!strcmp("FitBH", pdf_to_name(obj)))) { t_from_2 = 1; ld.ld.gotor.flags |= fz_link_flag_fit_h; } - else if ((!strcmp("FitV", fz_to_name(obj))) || (!strcmp("FitBV", fz_to_name(obj)))) + else if ((!strcmp("FitV", pdf_to_name(obj))) || (!strcmp("FitBV", pdf_to_name(obj)))) { l_from_2 = 1; ld.ld.gotor.flags |= fz_link_flag_fit_v; } - else if (!strcmp("FitR", fz_to_name(obj))) + else if (!strcmp("FitR", pdf_to_name(obj))) { l_from_2 = b_from_3 = r_from_4 = t_from_5 = 1; ld.ld.gotor.flags |= fz_link_flag_fit_h; @@ -104,77 +104,77 @@ pdf_parse_link_dest(pdf_document *xref, fz_obj *dest) if (l_from_2) { - obj = fz_array_get(dest, 2); - if (fz_is_int(obj)) + obj = pdf_array_get(dest, 2); + if (pdf_is_int(obj)) { ld.ld.gotor.flags |= fz_link_flag_l_valid; - ld.ld.gotor.lt.x = fz_to_int(obj); + ld.ld.gotor.lt.x = pdf_to_int(obj); } - else if (fz_is_real(obj)) + else if (pdf_is_real(obj)) { ld.ld.gotor.flags |= fz_link_flag_l_valid; - ld.ld.gotor.lt.x = fz_to_real(obj); + ld.ld.gotor.lt.x = pdf_to_real(obj); } } if (b_from_3) { - obj = fz_array_get(dest, 3); - if (fz_is_int(obj)) + obj = pdf_array_get(dest, 3); + if (pdf_is_int(obj)) { ld.ld.gotor.flags |= fz_link_flag_b_valid; - ld.ld.gotor.rb.y = fz_to_int(obj); + ld.ld.gotor.rb.y = pdf_to_int(obj); } - else if (fz_is_real(obj)) + else if (pdf_is_real(obj)) { ld.ld.gotor.flags |= fz_link_flag_b_valid; - ld.ld.gotor.rb.y = fz_to_real(obj); + ld.ld.gotor.rb.y = pdf_to_real(obj); } } if (r_from_4) { - obj = fz_array_get(dest, 4); - if (fz_is_int(obj)) + obj = pdf_array_get(dest, 4); + if (pdf_is_int(obj)) { ld.ld.gotor.flags |= fz_link_flag_r_valid; - ld.ld.gotor.rb.x = fz_to_int(obj); + ld.ld.gotor.rb.x = pdf_to_int(obj); } - else if (fz_is_real(obj)) + else if (pdf_is_real(obj)) { ld.ld.gotor.flags |= fz_link_flag_r_valid; - ld.ld.gotor.rb.x = fz_to_real(obj); + ld.ld.gotor.rb.x = pdf_to_real(obj); } } if (t_from_5 || t_from_3 || t_from_2) { if (t_from_5) - obj = fz_array_get(dest, 5); + obj = pdf_array_get(dest, 5); else if (t_from_3) - obj = fz_array_get(dest, 3); + obj = pdf_array_get(dest, 3); else - obj = fz_array_get(dest, 2); - if (fz_is_int(obj)) + obj = pdf_array_get(dest, 2); + if (pdf_is_int(obj)) { ld.ld.gotor.flags |= fz_link_flag_t_valid; - ld.ld.gotor.lt.y = fz_to_int(obj); + ld.ld.gotor.lt.y = pdf_to_int(obj); } - else if (fz_is_real(obj)) + else if (pdf_is_real(obj)) { ld.ld.gotor.flags |= fz_link_flag_t_valid; - ld.ld.gotor.lt.y = fz_to_real(obj); + ld.ld.gotor.lt.y = pdf_to_real(obj); } } if (z_from_4) { - obj = fz_array_get(dest, 4); - if (fz_is_int(obj)) + obj = pdf_array_get(dest, 4); + if (pdf_is_int(obj)) { ld.ld.gotor.flags |= fz_link_flag_r_valid; - ld.ld.gotor.rb.x = fz_to_int(obj); + ld.ld.gotor.rb.x = pdf_to_int(obj); } - else if (fz_is_real(obj)) + else if (pdf_is_real(obj)) { ld.ld.gotor.flags |= fz_link_flag_r_valid; - ld.ld.gotor.rb.x = fz_to_real(obj); + ld.ld.gotor.rb.x = pdf_to_real(obj); } } @@ -192,10 +192,10 @@ pdf_parse_link_dest(pdf_document *xref, fz_obj *dest) } fz_link_dest -pdf_parse_action(pdf_document *xref, fz_obj *action) +pdf_parse_action(pdf_document *xref, pdf_obj *action) { fz_link_dest ld; - fz_obj *obj, *dest; + pdf_obj *obj, *dest; fz_context *ctx = xref->ctx; ld.kind = FZ_LINK_NONE; @@ -203,53 +203,53 @@ pdf_parse_action(pdf_document *xref, fz_obj *action) if (!action) return ld; - obj = fz_dict_gets(action, "S"); - if (!strcmp(fz_to_name(obj), "GoTo")) + obj = pdf_dict_gets(action, "S"); + if (!strcmp(pdf_to_name(obj), "GoTo")) { - dest = fz_dict_gets(action, "D"); + dest = pdf_dict_gets(action, "D"); ld = pdf_parse_link_dest(xref, dest); } - else if (!strcmp(fz_to_name(obj), "URI")) + else if (!strcmp(pdf_to_name(obj), "URI")) { ld.kind = FZ_LINK_URI; - ld.ld.uri.is_map = fz_to_bool(fz_dict_gets(action, "IsMap")); - ld.ld.uri.uri = pdf_to_utf8(ctx, fz_dict_gets(action, "URI")); + ld.ld.uri.is_map = pdf_to_bool(pdf_dict_gets(action, "IsMap")); + ld.ld.uri.uri = pdf_to_utf8(ctx, pdf_dict_gets(action, "URI")); } - else if (!strcmp(fz_to_name(obj), "Launch")) + else if (!strcmp(pdf_to_name(obj), "Launch")) { ld.kind = FZ_LINK_LAUNCH; - ld.ld.launch.file_spec = pdf_to_utf8(ctx, fz_dict_gets(action, "F")); - ld.ld.launch.new_window = fz_to_int(fz_dict_gets(action, "NewWindow")); + ld.ld.launch.file_spec = pdf_to_utf8(ctx, pdf_dict_gets(action, "F")); + ld.ld.launch.new_window = pdf_to_int(pdf_dict_gets(action, "NewWindow")); } - else if (!strcmp(fz_to_name(obj), "Named")) + else if (!strcmp(pdf_to_name(obj), "Named")) { ld.kind = FZ_LINK_NAMED; - ld.ld.named.named = pdf_to_utf8(ctx, fz_dict_gets(action, "N")); + ld.ld.named.named = pdf_to_utf8(ctx, pdf_dict_gets(action, "N")); } - else if (!strcmp(fz_to_name(obj), "GoToR")) + else if (!strcmp(pdf_to_name(obj), "GoToR")) { - dest = fz_dict_gets(action, "D"); + dest = pdf_dict_gets(action, "D"); ld = pdf_parse_link_dest(xref, dest); ld.kind = FZ_LINK_GOTOR; - ld.ld.gotor.file_spec = pdf_to_utf8(ctx, fz_dict_gets(action, "F")); - ld.ld.gotor.new_window = fz_to_int(fz_dict_gets(action, "NewWindow")); + ld.ld.gotor.file_spec = pdf_to_utf8(ctx, pdf_dict_gets(action, "F")); + ld.ld.gotor.new_window = pdf_to_int(pdf_dict_gets(action, "NewWindow")); } return ld; } static fz_link * -pdf_load_link(pdf_document *xref, fz_obj *dict, fz_matrix page_ctm) +pdf_load_link(pdf_document *xref, pdf_obj *dict, fz_matrix page_ctm) { - fz_obj *dest = NULL; - fz_obj *action; - fz_obj *obj; + pdf_obj *dest = NULL; + pdf_obj *action; + pdf_obj *obj; fz_rect bbox; fz_context *ctx = xref->ctx; fz_link_dest ld; dest = NULL; - obj = fz_dict_gets(dict, "Rect"); + obj = pdf_dict_gets(dict, "Rect"); if (obj) bbox = pdf_to_rect(ctx, obj); else @@ -257,7 +257,7 @@ pdf_load_link(pdf_document *xref, fz_obj *dict, fz_matrix page_ctm) bbox = fz_transform_rect(page_ctm, bbox); - obj = fz_dict_gets(dict, "Dest"); + obj = pdf_dict_gets(dict, "Dest"); if (obj) { dest = resolve_dest(xref, obj); @@ -265,10 +265,10 @@ pdf_load_link(pdf_document *xref, fz_obj *dict, fz_matrix page_ctm) } else { - action = fz_dict_gets(dict, "A"); + action = pdf_dict_gets(dict, "A"); /* fall back to additional action button's down/up action */ if (!action) - action = fz_dict_getsa(fz_dict_gets(dict, "AA"), "U", "D"); + action = pdf_dict_getsa(pdf_dict_gets(dict, "AA"), "U", "D"); ld = pdf_parse_action(xref, action); } @@ -278,19 +278,19 @@ pdf_load_link(pdf_document *xref, fz_obj *dict, fz_matrix page_ctm) } fz_link * -pdf_load_link_annots(pdf_document *xref, fz_obj *annots, fz_matrix page_ctm) +pdf_load_link_annots(pdf_document *xref, pdf_obj *annots, fz_matrix page_ctm) { fz_link *link, *head, *tail; - fz_obj *obj; + pdf_obj *obj; int i, n; head = tail = NULL; link = NULL; - n = fz_array_len(annots); + n = pdf_array_len(annots); for (i = 0; i < n; i++) { - obj = fz_array_get(annots, i); + obj = pdf_array_get(annots, i); link = pdf_load_link(xref, obj, page_ctm); if (link) { @@ -318,7 +318,7 @@ pdf_free_annot(fz_context *ctx, pdf_annot *annot) if (annot->ap) pdf_drop_xobject(ctx, annot->ap); if (annot->obj) - fz_drop_obj(annot->obj); + pdf_drop_obj(annot->obj); fz_free(ctx, annot); annot = next; } @@ -349,10 +349,10 @@ pdf_transform_annot(pdf_annot *annot) } pdf_annot * -pdf_load_annots(pdf_document *xref, fz_obj *annots) +pdf_load_annots(pdf_document *xref, pdf_obj *annots) { pdf_annot *annot, *head, *tail; - fz_obj *obj, *ap, *as, *n, *rect; + pdf_obj *obj, *ap, *as, *n, *rect; pdf_xobject *form; int i, len; fz_context *ctx = xref->ctx; @@ -360,23 +360,23 @@ pdf_load_annots(pdf_document *xref, fz_obj *annots) head = tail = NULL; annot = NULL; - len = fz_array_len(annots); + len = pdf_array_len(annots); for (i = 0; i < len; i++) { - obj = fz_array_get(annots, i); + obj = pdf_array_get(annots, i); - rect = fz_dict_gets(obj, "Rect"); - ap = fz_dict_gets(obj, "AP"); - as = fz_dict_gets(obj, "AS"); - if (fz_is_dict(ap)) + rect = pdf_dict_gets(obj, "Rect"); + ap = pdf_dict_gets(obj, "AP"); + as = pdf_dict_gets(obj, "AS"); + if (pdf_is_dict(ap)) { - n = fz_dict_gets(ap, "N"); /* normal state */ + n = pdf_dict_gets(ap, "N"); /* normal state */ /* lookup current state in sub-dictionary */ - if (!pdf_is_stream(xref, fz_to_num(n), fz_to_gen(n))) - n = fz_dict_get(n, as); + if (!pdf_is_stream(xref, pdf_to_num(n), pdf_to_gen(n))) + n = pdf_dict_get(n, as); - if (pdf_is_stream(xref, fz_to_num(n), fz_to_gen(n))) + if (pdf_is_stream(xref, pdf_to_num(n), pdf_to_gen(n))) { fz_try(ctx) { @@ -389,7 +389,7 @@ pdf_load_annots(pdf_document *xref, fz_obj *annots) } annot = fz_malloc_struct(ctx, pdf_annot); - annot->obj = fz_keep_obj(obj); + annot->obj = pdf_keep_obj(obj); annot->rect = pdf_to_rect(ctx, rect); annot->ap = form; annot->next = NULL; diff --git a/pdf/pdf_cmap.c b/pdf/pdf_cmap.c index 987da592..3c4d07bc 100644 --- a/pdf/pdf_cmap.c +++ b/pdf/pdf_cmap.c @@ -15,8 +15,8 @@ * or can trust the parser to give us optimal mappings. */ -#include "fitz.h" -#include "mupdf.h" +#include "fitz-internal.h" +#include "mupdf-internal.h" /* Macros for accessing the combined extent_flags field */ #define pdf_range_high(r) ((r)->low + ((r)->extent_flags >> 2)) @@ -98,19 +98,19 @@ pdf_set_usecmap(fz_context *ctx, pdf_cmap *cmap, pdf_cmap *usecmap) } int -pdf_get_wmode(fz_context *ctx, pdf_cmap *cmap) +pdf_cmap_wmode(fz_context *ctx, pdf_cmap *cmap) { return cmap->wmode; } void -pdf_set_wmode(fz_context *ctx, pdf_cmap *cmap, int wmode) +pdf_set_cmap_wmode(fz_context *ctx, pdf_cmap *cmap, int wmode) { cmap->wmode = wmode; } void -pdf_debug_cmap(fz_context *ctx, pdf_cmap *cmap) +pdf_print_cmap(fz_context *ctx, pdf_cmap *cmap) { int i, k, n; diff --git a/pdf/pdf_cmap_load.c b/pdf/pdf_cmap_load.c index 3257516c..8ab7e646 100644 --- a/pdf/pdf_cmap_load.c +++ b/pdf/pdf_cmap_load.c @@ -1,5 +1,5 @@ -#include "fitz.h" -#include "mupdf.h" +#include "fitz-internal.h" +#include "mupdf-internal.h" unsigned int pdf_cmap_size(fz_context *ctx, pdf_cmap *cmap) @@ -16,13 +16,13 @@ pdf_cmap_size(fz_context *ctx, pdf_cmap *cmap) * Load CMap stream in PDF file */ pdf_cmap * -pdf_load_embedded_cmap(pdf_document *xref, fz_obj *stmobj) +pdf_load_embedded_cmap(pdf_document *xref, pdf_obj *stmobj) { fz_stream *file = NULL; pdf_cmap *cmap = NULL; pdf_cmap *usecmap; - fz_obj *wmode; - fz_obj *obj = NULL; + pdf_obj *wmode; + pdf_obj *obj = NULL; fz_context *ctx = xref->ctx; int phase = 0; @@ -31,31 +31,31 @@ pdf_load_embedded_cmap(pdf_document *xref, fz_obj *stmobj) fz_var(file); fz_var(cmap); - if ((cmap = fz_find_item(ctx, pdf_free_cmap_imp, stmobj))) + if ((cmap = pdf_find_item(ctx, pdf_free_cmap_imp, stmobj))) { return cmap; } fz_try(ctx) { - file = pdf_open_stream(xref, fz_to_num(stmobj), fz_to_gen(stmobj)); + file = pdf_open_stream(xref, pdf_to_num(stmobj), pdf_to_gen(stmobj)); phase = 1; cmap = pdf_load_cmap(ctx, file); phase = 2; fz_close(file); file = NULL; - wmode = fz_dict_gets(stmobj, "WMode"); - if (fz_is_int(wmode)) - pdf_set_wmode(ctx, cmap, fz_to_int(wmode)); - obj = fz_dict_gets(stmobj, "UseCMap"); - if (fz_is_name(obj)) + wmode = pdf_dict_gets(stmobj, "WMode"); + if (pdf_is_int(wmode)) + pdf_set_cmap_wmode(ctx, cmap, pdf_to_int(wmode)); + obj = pdf_dict_gets(stmobj, "UseCMap"); + if (pdf_is_name(obj)) { - usecmap = pdf_load_system_cmap(ctx, fz_to_name(obj)); + usecmap = pdf_load_system_cmap(ctx, pdf_to_name(obj)); pdf_set_usecmap(ctx, cmap, usecmap); pdf_drop_cmap(ctx, usecmap); } - else if (fz_is_indirect(obj)) + else if (pdf_is_indirect(obj)) { phase = 3; usecmap = pdf_load_embedded_cmap(xref, obj); @@ -63,7 +63,7 @@ pdf_load_embedded_cmap(pdf_document *xref, fz_obj *stmobj) pdf_drop_cmap(ctx, usecmap); } - fz_store_item(ctx, stmobj, cmap, pdf_cmap_size(ctx, cmap)); + pdf_store_item(ctx, stmobj, cmap, pdf_cmap_size(ctx, cmap)); } fz_catch(ctx) { @@ -72,13 +72,13 @@ pdf_load_embedded_cmap(pdf_document *xref, fz_obj *stmobj) if (cmap) pdf_drop_cmap(ctx, cmap); if (phase < 1) - fz_throw(ctx, "cannot open cmap stream (%d %d R)", fz_to_num(stmobj), fz_to_gen(stmobj)); + fz_throw(ctx, "cannot open cmap stream (%d %d R)", pdf_to_num(stmobj), pdf_to_gen(stmobj)); else if (phase < 2) - fz_throw(ctx, "cannot parse cmap stream (%d %d R)", fz_to_num(stmobj), fz_to_gen(stmobj)); + fz_throw(ctx, "cannot parse cmap stream (%d %d R)", pdf_to_num(stmobj), pdf_to_gen(stmobj)); else if (phase < 3) - fz_throw(ctx, "cannot load system usecmap '%s'", fz_to_name(obj)); + fz_throw(ctx, "cannot load system usecmap '%s'", pdf_to_name(obj)); else - fz_throw(ctx, "cannot load embedded usecmap (%d %d R)", fz_to_num(obj), fz_to_gen(obj)); + fz_throw(ctx, "cannot load embedded usecmap (%d %d R)", pdf_to_num(obj), pdf_to_gen(obj)); } return cmap; @@ -97,7 +97,7 @@ pdf_new_identity_cmap(fz_context *ctx, int wmode, int bytes) pdf_add_codespace(ctx, cmap, 0x0000, 0xffff, bytes); pdf_map_range_to_range(ctx, cmap, 0x0000, 0xffff, 0); pdf_sort_cmap(ctx, cmap); - pdf_set_wmode(ctx, cmap, wmode); + pdf_set_cmap_wmode(ctx, cmap, wmode); } fz_catch(ctx) { diff --git a/pdf/pdf_cmap_parse.c b/pdf/pdf_cmap_parse.c index fb37c4a9..93dd97c9 100644 --- a/pdf/pdf_cmap_parse.c +++ b/pdf/pdf_cmap_parse.c @@ -1,5 +1,5 @@ -#include "fitz.h" -#include "mupdf.h" +#include "fitz-internal.h" +#include "mupdf-internal.h" /* * CMap parser @@ -49,14 +49,14 @@ pdf_code_from_string(char *buf, int len) } static int -pdf_lex_cmap(fz_stream *file, char *buf, int n, int *sl) +pdf_lex_cmap(fz_stream *file, pdf_lexbuf *buf) { - int tok = pdf_lex(file, buf, n, sl); + int tok = pdf_lex(file, buf); /* RJW: Lost debugging here: "cannot parse cmap token" */ if (tok == PDF_TOK_KEYWORD) - tok = pdf_cmap_token_from_keyword(buf); + tok = pdf_cmap_token_from_keyword(buf->scratch); return tok; } @@ -64,15 +64,15 @@ pdf_lex_cmap(fz_stream *file, char *buf, int n, int *sl) static void pdf_parse_cmap_name(fz_context *ctx, pdf_cmap *cmap, fz_stream *file) { - char buf[256]; + pdf_lexbuf buf; int tok; - int len; - tok = pdf_lex_cmap(file, buf, sizeof buf, &len); + buf.size = PDF_LEXBUF_SMALL; + tok = pdf_lex_cmap(file, &buf); /* RJW: Lost debugging: "syntaxerror in cmap" */ if (tok == PDF_TOK_NAME) - fz_strlcpy(cmap->cmap_name, buf, sizeof(cmap->cmap_name)); + fz_strlcpy(cmap->cmap_name, buf.scratch, sizeof(cmap->cmap_name)); else fz_warn(ctx, "expected name after CMapName in cmap"); } @@ -80,15 +80,15 @@ pdf_parse_cmap_name(fz_context *ctx, pdf_cmap *cmap, fz_stream *file) static void pdf_parse_wmode(fz_context *ctx, pdf_cmap *cmap, fz_stream *file) { - char buf[256]; + pdf_lexbuf buf; int tok; - int len; - tok = pdf_lex_cmap(file, buf, sizeof buf, &len); + buf.size = PDF_LEXBUF_SMALL; + tok = pdf_lex_cmap(file, &buf); /* RJW: Lost debugging: "syntaxerror in cmap" */ if (tok == PDF_TOK_INT) - pdf_set_wmode(ctx, cmap, atoi(buf)); + pdf_set_cmap_wmode(ctx, cmap, buf.i); else fz_warn(ctx, "expected integer after WMode in cmap"); } @@ -96,14 +96,14 @@ pdf_parse_wmode(fz_context *ctx, pdf_cmap *cmap, fz_stream *file) static void pdf_parse_codespace_range(fz_context *ctx, pdf_cmap *cmap, fz_stream *file) { - char buf[256]; + pdf_lexbuf buf; int tok; - int len; int lo, hi; + buf.size = PDF_LEXBUF_SMALL; while (1) { - tok = pdf_lex_cmap(file, buf, sizeof buf, &len); + tok = pdf_lex_cmap(file, &buf); /* RJW: Lost debugging: "syntaxerror in cmap" */ if (tok == TOK_END_CODESPACE_RANGE) @@ -111,13 +111,13 @@ pdf_parse_codespace_range(fz_context *ctx, pdf_cmap *cmap, fz_stream *file) else if (tok == PDF_TOK_STRING) { - lo = pdf_code_from_string(buf, len); - tok = pdf_lex_cmap(file, buf, sizeof buf, &len); + lo = pdf_code_from_string(buf.scratch, buf.len); + tok = pdf_lex_cmap(file, &buf); /* RJW: Lost debugging: "syntaxerror in cmap" */ if (tok == PDF_TOK_STRING) { - hi = pdf_code_from_string(buf, len); - pdf_add_codespace(ctx, cmap, lo, hi, len); + hi = pdf_code_from_string(buf.scratch, buf.len); + pdf_add_codespace(ctx, cmap, lo, hi, buf.len); } else break; } @@ -131,14 +131,14 @@ pdf_parse_codespace_range(fz_context *ctx, pdf_cmap *cmap, fz_stream *file) static void pdf_parse_cid_range(fz_context *ctx, pdf_cmap *cmap, fz_stream *file) { - char buf[256]; + pdf_lexbuf buf; int tok; - int len; int lo, hi, dst; + buf.size = PDF_LEXBUF_SMALL; while (1) { - tok = pdf_lex_cmap(file, buf, sizeof buf, &len); + tok = pdf_lex_cmap(file, &buf); /* RJW: Lost debugging: "syntaxerror in cmap" */ if (tok == TOK_END_CID_RANGE) @@ -147,21 +147,21 @@ pdf_parse_cid_range(fz_context *ctx, pdf_cmap *cmap, fz_stream *file) else if (tok != PDF_TOK_STRING) fz_throw(ctx, "expected string or endcidrange"); - lo = pdf_code_from_string(buf, len); + lo = pdf_code_from_string(buf.scratch, buf.len); - tok = pdf_lex_cmap(file, buf, sizeof buf, &len); + tok = pdf_lex_cmap(file, &buf); /* RJW: Lost debugging: "syntaxerror in cmap" */ if (tok != PDF_TOK_STRING) fz_throw(ctx, "expected string"); - hi = pdf_code_from_string(buf, len); + hi = pdf_code_from_string(buf.scratch, buf.len); - tok = pdf_lex_cmap(file, buf, sizeof buf, &len); + tok = pdf_lex_cmap(file, &buf); /* RJW: Lost debugging: "syntaxerror in cmap" */ if (tok != PDF_TOK_INT) fz_throw(ctx, "expected integer"); - dst = atoi(buf); + dst = buf.i; pdf_map_range_to_range(ctx, cmap, lo, hi, dst); } @@ -170,14 +170,14 @@ pdf_parse_cid_range(fz_context *ctx, pdf_cmap *cmap, fz_stream *file) static void pdf_parse_cid_char(fz_context *ctx, pdf_cmap *cmap, fz_stream *file) { - char buf[256]; + pdf_lexbuf buf; int tok; - int len; int src, dst; + buf.size = PDF_LEXBUF_SMALL; while (1) { - tok = pdf_lex_cmap(file, buf, sizeof buf, &len); + tok = pdf_lex_cmap(file, &buf); /* RJW: "syntaxerror in cmap" */ if (tok == TOK_END_CID_CHAR) @@ -186,15 +186,15 @@ pdf_parse_cid_char(fz_context *ctx, pdf_cmap *cmap, fz_stream *file) else if (tok != PDF_TOK_STRING) fz_throw(ctx, "expected string or endcidchar"); - src = pdf_code_from_string(buf, len); + src = pdf_code_from_string(buf.scratch, buf.len); - tok = pdf_lex_cmap(file, buf, sizeof buf, &len); + tok = pdf_lex_cmap(file, &buf); /* RJW: "syntaxerror in cmap" */ if (tok != PDF_TOK_INT) fz_throw(ctx, "expected integer"); - dst = atoi(buf); + dst = buf.i; pdf_map_range_to_range(ctx, cmap, src, src, dst); } @@ -203,15 +203,15 @@ pdf_parse_cid_char(fz_context *ctx, pdf_cmap *cmap, fz_stream *file) static void pdf_parse_bf_range_array(fz_context *ctx, pdf_cmap *cmap, fz_stream *file, int lo, int hi) { - char buf[256]; + pdf_lexbuf buf; int tok; - int len; int dst[256]; int i; + buf.size = PDF_LEXBUF_SMALL; while (1) { - tok = pdf_lex_cmap(file, buf, sizeof buf, &len); + tok = pdf_lex_cmap(file, &buf); /* RJW: "syntaxerror in cmap" */ if (tok == PDF_TOK_CLOSE_ARRAY) @@ -221,12 +221,12 @@ pdf_parse_bf_range_array(fz_context *ctx, pdf_cmap *cmap, fz_stream *file, int l else if (tok != PDF_TOK_STRING) fz_throw(ctx, "expected string or ]"); - if (len / 2) + if (buf.len / 2) { - for (i = 0; i < len / 2; i++) - dst[i] = pdf_code_from_string(buf + i * 2, 2); + for (i = 0; i < buf.len / 2; i++) + dst[i] = pdf_code_from_string(&buf.scratch[i * 2], 2); - pdf_map_one_to_many(ctx, cmap, lo, dst, len / 2); + pdf_map_one_to_many(ctx, cmap, lo, dst, buf.len / 2); } lo ++; @@ -236,14 +236,14 @@ pdf_parse_bf_range_array(fz_context *ctx, pdf_cmap *cmap, fz_stream *file, int l static void pdf_parse_bf_range(fz_context *ctx, pdf_cmap *cmap, fz_stream *file) { - char buf[256]; + pdf_lexbuf buf; int tok; - int len; int lo, hi, dst; + buf.size = PDF_LEXBUF_SMALL; while (1) { - tok = pdf_lex_cmap(file, buf, sizeof buf, &len); + tok = pdf_lex_cmap(file, &buf); /* RJW: "syntaxerror in cmap" */ if (tok == TOK_END_BF_RANGE) @@ -252,23 +252,23 @@ pdf_parse_bf_range(fz_context *ctx, pdf_cmap *cmap, fz_stream *file) else if (tok != PDF_TOK_STRING) fz_throw(ctx, "expected string or endbfrange"); - lo = pdf_code_from_string(buf, len); + lo = pdf_code_from_string(buf.scratch, buf.len); - tok = pdf_lex_cmap(file, buf, sizeof buf, &len); + tok = pdf_lex_cmap(file, &buf); /* RJW: "syntaxerror in cmap" */ if (tok != PDF_TOK_STRING) fz_throw(ctx, "expected string"); - hi = pdf_code_from_string(buf, len); + hi = pdf_code_from_string(buf.scratch, buf.len); - tok = pdf_lex_cmap(file, buf, sizeof buf, &len); + tok = pdf_lex_cmap(file, &buf); /* RJW: "syntaxerror in cmap" */ if (tok == PDF_TOK_STRING) { - if (len == 2) + if (buf.len == 2) { - dst = pdf_code_from_string(buf, len); + dst = pdf_code_from_string(buf.scratch, buf.len); pdf_map_range_to_range(ctx, cmap, lo, hi, dst); } else @@ -276,10 +276,10 @@ pdf_parse_bf_range(fz_context *ctx, pdf_cmap *cmap, fz_stream *file) int dststr[256]; int i; - if (len / 2) + if (buf.len / 2) { - for (i = 0; i < len / 2; i++) - dststr[i] = pdf_code_from_string(buf + i * 2, 2); + for (i = 0; i < buf.len / 2; i++) + dststr[i] = pdf_code_from_string(&buf.scratch[i * 2], 2); while (lo <= hi) { @@ -307,16 +307,16 @@ pdf_parse_bf_range(fz_context *ctx, pdf_cmap *cmap, fz_stream *file) static void pdf_parse_bf_char(fz_context *ctx, pdf_cmap *cmap, fz_stream *file) { - char buf[256]; + pdf_lexbuf buf; int tok; - int len; int dst[256]; int src; int i; + buf.size = PDF_LEXBUF_SMALL; while (1) { - tok = pdf_lex_cmap(file, buf, sizeof buf, &len); + tok = pdf_lex_cmap(file, &buf); /* RJW: "syntaxerror in cmap" */ if (tok == TOK_END_BF_CHAR) @@ -325,18 +325,18 @@ pdf_parse_bf_char(fz_context *ctx, pdf_cmap *cmap, fz_stream *file) else if (tok != PDF_TOK_STRING) fz_throw(ctx, "expected string or endbfchar"); - src = pdf_code_from_string(buf, len); + src = pdf_code_from_string(buf.scratch, buf.len); - tok = pdf_lex_cmap(file, buf, sizeof buf, &len); + tok = pdf_lex_cmap(file, &buf); /* RJW: "syntaxerror in cmap" */ /* Note: does not handle /dstName */ if (tok != PDF_TOK_STRING) fz_throw(ctx, "expected string"); - if (len / 2) + if (buf.len / 2) { - for (i = 0; i < len / 2; i++) - dst[i] = pdf_code_from_string(buf + i * 2, 2); + for (i = 0; i < buf.len / 2; i++) + dst[i] = pdf_code_from_string(&buf.scratch[i * 2], 2); pdf_map_one_to_many(ctx, cmap, src, dst, i); } } @@ -347,11 +347,11 @@ pdf_load_cmap(fz_context *ctx, fz_stream *file) { pdf_cmap *cmap; char key[64]; - char buf[256]; + pdf_lexbuf buf; int tok; - int len; const char *where; + buf.size = PDF_LEXBUF_SMALL; cmap = pdf_new_cmap(ctx); strcpy(key, ".notdef"); @@ -363,25 +363,25 @@ pdf_load_cmap(fz_context *ctx, fz_stream *file) while (1) { where = ""; - tok = pdf_lex_cmap(file, buf, sizeof buf, &len); + tok = pdf_lex_cmap(file, &buf); if (tok == PDF_TOK_EOF || tok == TOK_END_CMAP) break; else if (tok == PDF_TOK_NAME) { - if (!strcmp(buf, "CMapName")) + if (!strcmp(buf.scratch, "CMapName")) { where = " after CMapName"; pdf_parse_cmap_name(ctx, cmap, file); } - else if (!strcmp(buf, "WMode")) + else if (!strcmp(buf.scratch, "WMode")) { where = " after WMode"; pdf_parse_wmode(ctx, cmap, file); } else - fz_strlcpy(key, buf, sizeof key); + fz_strlcpy(key, buf.scratch, sizeof key); } else if (tok == TOK_USECMAP) diff --git a/pdf/pdf_cmap_table.c b/pdf/pdf_cmap_table.c index fbe528e0..21dfe5fa 100644 --- a/pdf/pdf_cmap_table.c +++ b/pdf/pdf_cmap_table.c @@ -1,5 +1,5 @@ -#include "fitz.h" -#include "mupdf.h" +#include "fitz-internal.h" +#include "mupdf-internal.h" #ifndef NOCJK #include "../generated/cmap_cns.h" diff --git a/pdf/pdf_colorspace.c b/pdf/pdf_colorspace.c index 7a410df8..ee5bc5fc 100644 --- a/pdf/pdf_colorspace.c +++ b/pdf/pdf_colorspace.c @@ -1,14 +1,14 @@ -#include "fitz.h" -#include "mupdf.h" +#include "fitz-internal.h" +#include "mupdf-internal.h" /* ICCBased */ static fz_colorspace * -load_icc_based(pdf_document *xref, fz_obj *dict) +load_icc_based(pdf_document *xref, pdf_obj *dict) { int n; - n = fz_to_int(fz_dict_gets(dict, "N")); + n = pdf_to_int(pdf_dict_gets(dict, "N")); switch (n) { @@ -91,14 +91,14 @@ free_separation(fz_context *ctx, fz_colorspace *cs) } static fz_colorspace * -load_separation(pdf_document *xref, fz_obj *array) +load_separation(pdf_document *xref, pdf_obj *array) { fz_colorspace *cs; struct separation *sep = NULL; fz_context *ctx = xref->ctx; - fz_obj *nameobj = fz_array_get(array, 1); - fz_obj *baseobj = fz_array_get(array, 2); - fz_obj *tintobj = fz_array_get(array, 3); + pdf_obj *nameobj = pdf_array_get(array, 1); + pdf_obj *baseobj = pdf_array_get(array, 2); + pdf_obj *tintobj = pdf_array_get(array, 3); fz_colorspace *base; pdf_function *tint = NULL; int n; @@ -106,8 +106,8 @@ load_separation(pdf_document *xref, fz_obj *array) fz_var(tint); fz_var(sep); - if (fz_is_array(nameobj)) - n = fz_array_len(nameobj); + if (pdf_is_array(nameobj)) + n = pdf_array_len(nameobj); else n = 1; @@ -115,13 +115,13 @@ load_separation(pdf_document *xref, fz_obj *array) fz_throw(ctx, "too many components in colorspace"); base = pdf_load_colorspace(xref, baseobj); - /* RJW: "cannot load base colorspace (%d %d R)", fz_to_num(baseobj), fz_to_gen(baseobj) */ + /* RJW: "cannot load base colorspace (%d %d R)", pdf_to_num(baseobj), pdf_to_gen(baseobj) */ fz_try(ctx) { tint = pdf_load_function(xref, tintobj); /* RJW: fz_drop_colorspace(ctx, base); - * "cannot load tint function (%d %d R)", fz_to_num(tintobj), fz_to_gen(tintobj) */ + * "cannot load tint function (%d %d R)", pdf_to_num(tintobj), pdf_to_gen(tintobj) */ sep = fz_malloc_struct(ctx, struct separation); sep->base = base; @@ -193,7 +193,7 @@ pdf_expand_indexed_pixmap(fz_context *ctx, fz_pixmap *src) lookup = idx->lookup; n = idx->base->n; - dst = fz_new_pixmap_with_rect(ctx, idx->base, fz_bound_pixmap(src)); + dst = fz_new_pixmap_with_bbox(ctx, idx->base, fz_pixmap_bbox(ctx, src)); s = src->samples; d = dst->samples; @@ -210,21 +210,19 @@ pdf_expand_indexed_pixmap(fz_context *ctx, fz_pixmap *src) } } - if (src->mask) - dst->mask = fz_keep_pixmap(ctx, src->mask); dst->interpolate = src->interpolate; return dst; } static fz_colorspace * -load_indexed(pdf_document *xref, fz_obj *array) +load_indexed(pdf_document *xref, pdf_obj *array) { struct indexed *idx = NULL; fz_context *ctx = xref->ctx; - fz_obj *baseobj = fz_array_get(array, 1); - fz_obj *highobj = fz_array_get(array, 2); - fz_obj *lookup = fz_array_get(array, 3); + pdf_obj *baseobj = pdf_array_get(array, 1); + pdf_obj *highobj = pdf_array_get(array, 2); + pdf_obj *lookup = pdf_array_get(array, 3); fz_colorspace *base = NULL; fz_colorspace *cs = NULL; int i, n; @@ -236,12 +234,12 @@ load_indexed(pdf_document *xref, fz_obj *array) fz_try(ctx) { base = pdf_load_colorspace(xref, baseobj); - /* "cannot load base colorspace (%d %d R)", fz_to_num(baseobj), fz_to_gen(baseobj) */ + /* "cannot load base colorspace (%d %d R)", pdf_to_num(baseobj), pdf_to_gen(baseobj) */ idx = fz_malloc_struct(ctx, struct indexed); idx->lookup = NULL; idx->base = base; - idx->high = fz_to_int(highobj); + idx->high = pdf_to_int(highobj); idx->high = CLAMP(idx->high, 0, 255); n = base->n * (idx->high + 1); idx->lookup = fz_malloc_array(ctx, 1, n); @@ -252,30 +250,30 @@ load_indexed(pdf_document *xref, fz_obj *array) cs->data = idx; cs->size += sizeof(*idx) + n + (base ? base->size : 0); - if (fz_is_string(lookup) && fz_to_str_len(lookup) == n) + if (pdf_is_string(lookup) && pdf_to_str_len(lookup) == n) { - unsigned char *buf = (unsigned char *) fz_to_str_buf(lookup); + unsigned char *buf = (unsigned char *) pdf_to_str_buf(lookup); for (i = 0; i < n; i++) idx->lookup[i] = buf[i]; } - else if (fz_is_indirect(lookup)) + else if (pdf_is_indirect(lookup)) { fz_stream *file = NULL; fz_try(ctx) { - file = pdf_open_stream(xref, fz_to_num(lookup), fz_to_gen(lookup)); + file = pdf_open_stream(xref, pdf_to_num(lookup), pdf_to_gen(lookup)); } fz_catch(ctx) { - fz_throw(ctx, "cannot open colorspace lookup table (%d 0 R)", fz_to_num(lookup)); + fz_throw(ctx, "cannot open colorspace lookup table (%d 0 R)", pdf_to_num(lookup)); } i = fz_read(file, idx->lookup, n); if (i < 0) { fz_close(file); - fz_throw(ctx, "cannot read colorspace lookup table (%d 0 R)", fz_to_num(lookup)); + fz_throw(ctx, "cannot read colorspace lookup table (%d 0 R)", pdf_to_num(lookup)); } fz_close(file); @@ -304,106 +302,106 @@ load_indexed(pdf_document *xref, fz_obj *array) /* Parse and create colorspace from PDF object */ static fz_colorspace * -pdf_load_colorspace_imp(pdf_document *xref, fz_obj *obj) +pdf_load_colorspace_imp(pdf_document *xref, pdf_obj *obj) { - if (fz_is_name(obj)) + if (pdf_is_name(obj)) { - if (!strcmp(fz_to_name(obj), "Pattern")) + if (!strcmp(pdf_to_name(obj), "Pattern")) return fz_device_gray; - else if (!strcmp(fz_to_name(obj), "G")) + else if (!strcmp(pdf_to_name(obj), "G")) return fz_device_gray; - else if (!strcmp(fz_to_name(obj), "RGB")) + else if (!strcmp(pdf_to_name(obj), "RGB")) return fz_device_rgb; - else if (!strcmp(fz_to_name(obj), "CMYK")) + else if (!strcmp(pdf_to_name(obj), "CMYK")) return fz_device_cmyk; - else if (!strcmp(fz_to_name(obj), "DeviceGray")) + else if (!strcmp(pdf_to_name(obj), "DeviceGray")) return fz_device_gray; - else if (!strcmp(fz_to_name(obj), "DeviceRGB")) + else if (!strcmp(pdf_to_name(obj), "DeviceRGB")) return fz_device_rgb; - else if (!strcmp(fz_to_name(obj), "DeviceCMYK")) + else if (!strcmp(pdf_to_name(obj), "DeviceCMYK")) return fz_device_cmyk; else - fz_throw(xref->ctx, "unknown colorspace: %s", fz_to_name(obj)); + fz_throw(xref->ctx, "unknown colorspace: %s", pdf_to_name(obj)); } - else if (fz_is_array(obj)) + else if (pdf_is_array(obj)) { - fz_obj *name = fz_array_get(obj, 0); + pdf_obj *name = pdf_array_get(obj, 0); - if (fz_is_name(name)) + if (pdf_is_name(name)) { /* load base colorspace instead */ - if (!strcmp(fz_to_name(name), "Pattern")) + if (!strcmp(pdf_to_name(name), "Pattern")) { - obj = fz_array_get(obj, 1); + obj = pdf_array_get(obj, 1); if (!obj) { return fz_device_gray; } return pdf_load_colorspace(xref, obj); - /* RJW: "cannot load pattern (%d %d R)", fz_to_num(obj), fz_to_gen(obj) */ + /* RJW: "cannot load pattern (%d %d R)", pdf_to_num(obj), pdf_to_gen(obj) */ } - else if (!strcmp(fz_to_name(name), "G")) + else if (!strcmp(pdf_to_name(name), "G")) return fz_device_gray; - else if (!strcmp(fz_to_name(name), "RGB")) + else if (!strcmp(pdf_to_name(name), "RGB")) return fz_device_rgb; - else if (!strcmp(fz_to_name(name), "CMYK")) + else if (!strcmp(pdf_to_name(name), "CMYK")) return fz_device_cmyk; - else if (!strcmp(fz_to_name(name), "DeviceGray")) + else if (!strcmp(pdf_to_name(name), "DeviceGray")) return fz_device_gray; - else if (!strcmp(fz_to_name(name), "DeviceRGB")) + else if (!strcmp(pdf_to_name(name), "DeviceRGB")) return fz_device_rgb; - else if (!strcmp(fz_to_name(name), "DeviceCMYK")) + else if (!strcmp(pdf_to_name(name), "DeviceCMYK")) return fz_device_cmyk; - else if (!strcmp(fz_to_name(name), "CalGray")) + else if (!strcmp(pdf_to_name(name), "CalGray")) return fz_device_gray; - else if (!strcmp(fz_to_name(name), "CalRGB")) + else if (!strcmp(pdf_to_name(name), "CalRGB")) return fz_device_rgb; - else if (!strcmp(fz_to_name(name), "CalCMYK")) + else if (!strcmp(pdf_to_name(name), "CalCMYK")) return fz_device_cmyk; - else if (!strcmp(fz_to_name(name), "Lab")) + else if (!strcmp(pdf_to_name(name), "Lab")) return fz_device_lab; - else if (!strcmp(fz_to_name(name), "ICCBased")) - return load_icc_based(xref, fz_array_get(obj, 1)); + else if (!strcmp(pdf_to_name(name), "ICCBased")) + return load_icc_based(xref, pdf_array_get(obj, 1)); - else if (!strcmp(fz_to_name(name), "Indexed")) + else if (!strcmp(pdf_to_name(name), "Indexed")) return load_indexed(xref, obj); - else if (!strcmp(fz_to_name(name), "I")) + else if (!strcmp(pdf_to_name(name), "I")) return load_indexed(xref, obj); - else if (!strcmp(fz_to_name(name), "Separation")) + else if (!strcmp(pdf_to_name(name), "Separation")) return load_separation(xref, obj); - else if (!strcmp(fz_to_name(name), "DeviceN")) + else if (!strcmp(pdf_to_name(name), "DeviceN")) return load_separation(xref, obj); else - fz_throw(xref->ctx, "syntaxerror: unknown colorspace %s", fz_to_name(name)); + fz_throw(xref->ctx, "syntaxerror: unknown colorspace %s", pdf_to_name(name)); } } - fz_throw(xref->ctx, "syntaxerror: could not parse color space (%d %d R)", fz_to_num(obj), fz_to_gen(obj)); + fz_throw(xref->ctx, "syntaxerror: could not parse color space (%d %d R)", pdf_to_num(obj), pdf_to_gen(obj)); return NULL; /* Stupid MSVC */ } fz_colorspace * -pdf_load_colorspace(pdf_document *xref, fz_obj *obj) +pdf_load_colorspace(pdf_document *xref, pdf_obj *obj) { fz_context *ctx = xref->ctx; fz_colorspace *cs; - if ((cs = fz_find_item(ctx, fz_free_colorspace_imp, obj))) + if ((cs = pdf_find_item(ctx, fz_free_colorspace_imp, obj))) { return cs; } cs = pdf_load_colorspace_imp(xref, obj); - /* RJW: "cannot load colorspace (%d %d R)", fz_to_num(obj), fz_to_gen(obj) */ + /* RJW: "cannot load colorspace (%d %d R)", pdf_to_num(obj), pdf_to_gen(obj) */ - fz_store_item(ctx, obj, cs, cs->size); + pdf_store_item(ctx, obj, cs, cs->size); return cs; } diff --git a/pdf/pdf_crypt.c b/pdf/pdf_crypt.c index 59423a38..b65786d9 100644 --- a/pdf/pdf_crypt.c +++ b/pdf/pdf_crypt.c @@ -1,5 +1,5 @@ -#include "fitz.h" -#include "mupdf.h" +#include "fitz-internal.h" +#include "mupdf-internal.h" enum { @@ -20,11 +20,11 @@ struct pdf_crypt_filter_s struct pdf_crypt_s { - fz_obj *id; + pdf_obj *id; int v; int length; - fz_obj *cf; + pdf_obj *cf; pdf_crypt_filter stmf; pdf_crypt_filter strf; @@ -40,7 +40,7 @@ struct pdf_crypt_s fz_context *ctx; }; -static void pdf_parse_crypt_filter(fz_context *ctx, pdf_crypt_filter *cf, fz_obj *dict, char *name, int defaultlength); +static void pdf_parse_crypt_filter(fz_context *ctx, pdf_crypt_filter *cf, pdf_obj *dict, char *name, int defaultlength); /* * Create crypt object for decrypting strings and streams @@ -48,31 +48,31 @@ static void pdf_parse_crypt_filter(fz_context *ctx, pdf_crypt_filter *cf, fz_obj */ pdf_crypt * -pdf_new_crypt(fz_context *ctx, fz_obj *dict, fz_obj *id) +pdf_new_crypt(fz_context *ctx, pdf_obj *dict, pdf_obj *id) { pdf_crypt *crypt; - fz_obj *obj; + pdf_obj *obj; crypt = fz_malloc_struct(ctx, pdf_crypt); /* Common to all security handlers (PDF 1.7 table 3.18) */ - obj = fz_dict_gets(dict, "Filter"); - if (!fz_is_name(obj)) + obj = pdf_dict_gets(dict, "Filter"); + if (!pdf_is_name(obj)) { pdf_free_crypt(ctx, crypt); fz_throw(ctx, "unspecified encryption handler"); } - if (strcmp(fz_to_name(obj), "Standard") != 0) + if (strcmp(pdf_to_name(obj), "Standard") != 0) { pdf_free_crypt(ctx, crypt); - fz_throw(ctx, "unknown encryption handler: '%s'", fz_to_name(obj)); + fz_throw(ctx, "unknown encryption handler: '%s'", pdf_to_name(obj)); } crypt->v = 0; - obj = fz_dict_gets(dict, "V"); - if (fz_is_int(obj)) - crypt->v = fz_to_int(obj); + obj = pdf_dict_gets(dict, "V"); + if (pdf_is_int(obj)) + crypt->v = pdf_to_int(obj); if (crypt->v != 1 && crypt->v != 2 && crypt->v != 4 && crypt->v != 5) { pdf_free_crypt(ctx, crypt); @@ -82,9 +82,9 @@ pdf_new_crypt(fz_context *ctx, fz_obj *dict, fz_obj *id) crypt->length = 40; if (crypt->v == 2 || crypt->v == 4) { - obj = fz_dict_gets(dict, "Length"); - if (fz_is_int(obj)) - crypt->length = fz_to_int(obj); + obj = pdf_dict_gets(dict, "Length"); + if (pdf_is_int(obj)) + crypt->length = pdf_to_int(obj); /* work-around for pdf generators that assume length is in bytes */ if (crypt->length < 40) @@ -122,10 +122,10 @@ pdf_new_crypt(fz_context *ctx, fz_obj *dict, fz_obj *id) crypt->strf.method = PDF_CRYPT_NONE; crypt->strf.length = crypt->length; - obj = fz_dict_gets(dict, "CF"); - if (fz_is_dict(obj)) + obj = pdf_dict_gets(dict, "CF"); + if (pdf_is_dict(obj)) { - crypt->cf = fz_keep_obj(obj); + crypt->cf = pdf_keep_obj(obj); } else { @@ -134,18 +134,18 @@ pdf_new_crypt(fz_context *ctx, fz_obj *dict, fz_obj *id) fz_try(ctx) { - obj = fz_dict_gets(dict, "StmF"); - if (fz_is_name(obj)) - pdf_parse_crypt_filter(ctx, &crypt->stmf, crypt->cf, fz_to_name(obj), crypt->length); + obj = pdf_dict_gets(dict, "StmF"); + if (pdf_is_name(obj)) + pdf_parse_crypt_filter(ctx, &crypt->stmf, crypt->cf, pdf_to_name(obj), crypt->length); - obj = fz_dict_gets(dict, "StrF"); - if (fz_is_name(obj)) - pdf_parse_crypt_filter(ctx, &crypt->strf, crypt->cf, fz_to_name(obj), crypt->length); + obj = pdf_dict_gets(dict, "StrF"); + if (pdf_is_name(obj)) + pdf_parse_crypt_filter(ctx, &crypt->strf, crypt->cf, pdf_to_name(obj), crypt->length); } fz_catch(ctx) { pdf_free_crypt(ctx, crypt); - fz_throw(ctx, "cannot parse string crypt filter (%d %d R)", fz_to_num(obj), fz_to_gen(obj)); + fz_throw(ctx, "cannot parse string crypt filter (%d %d R)", pdf_to_num(obj), pdf_to_gen(obj)); } /* in crypt revision 4, the crypt filter determines the key length */ @@ -155,36 +155,46 @@ pdf_new_crypt(fz_context *ctx, fz_obj *dict, fz_obj *id) /* Standard security handler (PDF 1.7 table 3.19) */ - obj = fz_dict_gets(dict, "R"); - if (fz_is_int(obj)) - crypt->r = fz_to_int(obj); + obj = pdf_dict_gets(dict, "R"); + if (pdf_is_int(obj)) + crypt->r = pdf_to_int(obj); + else if (crypt->v <= 4) + { + fz_warn(ctx, "encryption dictionary missing revision value, guessing..."); + if (crypt->v < 2) + crypt->r = 2; + else if (crypt->v == 2 || crypt->v == 3) + crypt->r = 3; + else if (crypt->v == 4) + crypt->r = 4; + } else { pdf_free_crypt(ctx, crypt); - fz_throw(ctx, "encryption dictionary missing revision value"); + fz_throw(ctx, "encryption dictionary missing version and revision value"); } - obj = fz_dict_gets(dict, "O"); - if (fz_is_string(obj) && fz_to_str_len(obj) == 32) - memcpy(crypt->o, fz_to_str_buf(obj), 32); + obj = pdf_dict_gets(dict, "O"); + if (pdf_is_string(obj) && pdf_to_str_len(obj) == 32) + memcpy(crypt->o, pdf_to_str_buf(obj), 32); /* /O and /U are supposed to be 48 bytes long for revision 5, they're often longer, though */ - else if (crypt->r == 5 && fz_is_string(obj) && fz_to_str_len(obj) >= 48) - memcpy(crypt->o, fz_to_str_buf(obj), 48); + else if (crypt->r == 5 && pdf_is_string(obj) && pdf_to_str_len(obj) >= 48) + memcpy(crypt->o, pdf_to_str_buf(obj), 48); else { pdf_free_crypt(ctx, crypt); fz_throw(ctx, "encryption dictionary missing owner password"); } - obj = fz_dict_gets(dict, "U"); - if (fz_is_string(obj) && fz_to_str_len(obj) == 32) - memcpy(crypt->u, fz_to_str_buf(obj), 32); - else if (fz_is_string(obj) && fz_to_str_len(obj) >= 48 && crypt->r == 5) - memcpy(crypt->u, fz_to_str_buf(obj), 48); - else if (fz_is_string(obj) && fz_to_str_len(obj) < 32) + obj = pdf_dict_gets(dict, "U"); + if (pdf_is_string(obj) && pdf_to_str_len(obj) == 32) + memcpy(crypt->u, pdf_to_str_buf(obj), 32); + else if (pdf_is_string(obj) && pdf_to_str_len(obj) >= 48 && crypt->r == 5) + memcpy(crypt->u, pdf_to_str_buf(obj), 48); + else if (pdf_is_string(obj) && pdf_to_str_len(obj) < 32) { - fz_warn(ctx, "encryption password key too short (%d)", fz_to_str_len(obj)); - memcpy(crypt->u, fz_to_str_buf(obj), fz_to_str_len(obj)); + fz_warn(ctx, "encryption password key too short (%d)", pdf_to_str_len(obj)); + memcpy(crypt->u, pdf_to_str_buf(obj), pdf_to_str_len(obj)); } else { @@ -192,46 +202,46 @@ pdf_new_crypt(fz_context *ctx, fz_obj *dict, fz_obj *id) fz_throw(ctx, "encryption dictionary missing user password"); } - obj = fz_dict_gets(dict, "P"); - if (fz_is_int(obj)) - crypt->p = fz_to_int(obj); + obj = pdf_dict_gets(dict, "P"); + if (pdf_is_int(obj)) + crypt->p = pdf_to_int(obj); else { - pdf_free_crypt(ctx, crypt); - fz_throw(ctx, "encryption dictionary missing permissions value"); + fz_warn(ctx, "encryption dictionary missing permissions"); + crypt->p = 0xfffffffc; } if (crypt->r == 5) { - obj = fz_dict_gets(dict, "OE"); - if (!fz_is_string(obj) || fz_to_str_len(obj) != 32) + obj = pdf_dict_gets(dict, "OE"); + if (!pdf_is_string(obj) || pdf_to_str_len(obj) != 32) { pdf_free_crypt(ctx, crypt); fz_throw(ctx, "encryption dictionary missing owner encryption key"); } - memcpy(crypt->oe, fz_to_str_buf(obj), 32); + memcpy(crypt->oe, pdf_to_str_buf(obj), 32); - obj = fz_dict_gets(dict, "UE"); - if (!fz_is_string(obj) || fz_to_str_len(obj) != 32) + obj = pdf_dict_gets(dict, "UE"); + if (!pdf_is_string(obj) || pdf_to_str_len(obj) != 32) { pdf_free_crypt(ctx, crypt); fz_throw(ctx, "encryption dictionary missing user encryption key"); } - memcpy(crypt->ue, fz_to_str_buf(obj), 32); + memcpy(crypt->ue, pdf_to_str_buf(obj), 32); } crypt->encrypt_metadata = 1; - obj = fz_dict_gets(dict, "EncryptMetadata"); - if (fz_is_bool(obj)) - crypt->encrypt_metadata = fz_to_bool(obj); + obj = pdf_dict_gets(dict, "EncryptMetadata"); + if (pdf_is_bool(obj)) + crypt->encrypt_metadata = pdf_to_bool(obj); /* Extract file identifier string */ - if (fz_is_array(id) && fz_array_len(id) == 2) + if (pdf_is_array(id) && pdf_array_len(id) == 2) { - obj = fz_array_get(id, 0); - if (fz_is_string(obj)) - crypt->id = fz_keep_obj(obj); + obj = pdf_array_get(id, 0); + if (pdf_is_string(obj)) + crypt->id = pdf_keep_obj(obj); } else fz_warn(ctx, "missing file identifier, may not be able to do decryption"); @@ -242,8 +252,8 @@ pdf_new_crypt(fz_context *ctx, fz_obj *dict, fz_obj *id) void pdf_free_crypt(fz_context *ctx, pdf_crypt *crypt) { - if (crypt->id) fz_drop_obj(crypt->id); - if (crypt->cf) fz_drop_obj(crypt->cf); + if (crypt->id) pdf_drop_obj(crypt->id); + if (crypt->cf) pdf_drop_obj(crypt->cf); fz_free(ctx, crypt); } @@ -252,15 +262,15 @@ pdf_free_crypt(fz_context *ctx, pdf_crypt *crypt) */ static void -pdf_parse_crypt_filter(fz_context *ctx, pdf_crypt_filter *cf, fz_obj *cf_obj, char *name, int defaultlength) +pdf_parse_crypt_filter(fz_context *ctx, pdf_crypt_filter *cf, pdf_obj *cf_obj, char *name, int defaultlength) { - fz_obj *obj; - fz_obj *dict; + pdf_obj *obj; + pdf_obj *dict; int is_identity = (strcmp(name, "Identity") == 0); int is_stdcf = (!is_identity && (strcmp(name, "StdCF") == 0)); if (!is_identity && !is_stdcf) - fz_throw(ctx, "Crypt Filter not Identity or StdCF (%d %d R)", fz_to_num(cf_obj), fz_to_gen(cf_obj)); + fz_throw(ctx, "Crypt Filter not Identity or StdCF (%d %d R)", pdf_to_num(cf_obj), pdf_to_gen(cf_obj)); cf->method = PDF_CRYPT_NONE; cf->length = defaultlength; @@ -271,28 +281,28 @@ pdf_parse_crypt_filter(fz_context *ctx, pdf_crypt_filter *cf, fz_obj *cf_obj, ch return; } - dict = fz_dict_gets(cf_obj, name); - if (!fz_is_dict(dict)) - fz_throw(ctx, "cannot parse crypt filter (%d %d R)", fz_to_num(cf_obj), fz_to_gen(cf_obj)); + dict = pdf_dict_gets(cf_obj, name); + if (!pdf_is_dict(dict)) + fz_throw(ctx, "cannot parse crypt filter (%d %d R)", pdf_to_num(cf_obj), pdf_to_gen(cf_obj)); - obj = fz_dict_gets(dict, "CFM"); - if (fz_is_name(obj)) + obj = pdf_dict_gets(dict, "CFM"); + if (pdf_is_name(obj)) { - if (!strcmp(fz_to_name(obj), "None")) + if (!strcmp(pdf_to_name(obj), "None")) cf->method = PDF_CRYPT_NONE; - else if (!strcmp(fz_to_name(obj), "V2")) + else if (!strcmp(pdf_to_name(obj), "V2")) cf->method = PDF_CRYPT_RC4; - else if (!strcmp(fz_to_name(obj), "AESV2")) + else if (!strcmp(pdf_to_name(obj), "AESV2")) cf->method = PDF_CRYPT_AESV2; - else if (!strcmp(fz_to_name(obj), "AESV3")) + else if (!strcmp(pdf_to_name(obj), "AESV3")) cf->method = PDF_CRYPT_AESV3; else - fz_warn(ctx, "unknown encryption method: %s", fz_to_name(obj)); + fz_warn(ctx, "unknown encryption method: %s", pdf_to_name(obj)); } - obj = fz_dict_gets(dict, "Length"); - if (fz_is_int(obj)) - cf->length = fz_to_int(obj); + obj = pdf_dict_gets(dict, "Length"); + if (pdf_is_int(obj)) + cf->length = pdf_to_int(obj); /* the length for crypt filters is supposed to be in bytes not bits */ if (cf->length < 40) @@ -346,7 +356,7 @@ pdf_compute_encryption_key(pdf_crypt *crypt, unsigned char *password, int pwlen, fz_md5_update(&md5, buf, 4); /* Step 5 - pass first element of ID array */ - fz_md5_update(&md5, (unsigned char *)fz_to_str_buf(crypt->id), fz_to_str_len(crypt->id)); + fz_md5_update(&md5, (unsigned char *)pdf_to_str_buf(crypt->id), pdf_to_str_len(crypt->id)); /* Step 6 (revision 4 or greater) - if metadata is not encrypted pass 0xFFFFFFFF */ if (crypt->r >= 4) @@ -455,7 +465,7 @@ pdf_compute_user_password(pdf_crypt *crypt, unsigned char *password, int pwlen, fz_md5_init(&md5); fz_md5_update(&md5, padding, 32); - fz_md5_update(&md5, (unsigned char*)fz_to_str_buf(crypt->id), fz_to_str_len(crypt->id)); + fz_md5_update(&md5, (unsigned char*)pdf_to_str_buf(crypt->id), pdf_to_str_len(crypt->id)); fz_md5_final(&md5, digest); fz_arc4_init(&arc4, crypt->key, n); @@ -608,7 +618,7 @@ pdf_has_permission(pdf_document *xref, int p) } unsigned char * -pdf_get_crypt_key(pdf_document *xref) +pdf_crypt_key(pdf_document *xref) { if (xref->crypt) return xref->crypt->key; @@ -616,7 +626,7 @@ pdf_get_crypt_key(pdf_document *xref) } int -pdf_get_crypt_revision(pdf_document *xref) +pdf_crypt_revision(pdf_document *xref) { if (xref->crypt) return xref->crypt->v; @@ -624,7 +634,7 @@ pdf_get_crypt_revision(pdf_document *xref) } char * -pdf_get_crypt_method(pdf_document *xref) +pdf_crypt_method(pdf_document *xref) { if (xref->crypt) { @@ -641,7 +651,7 @@ pdf_get_crypt_method(pdf_document *xref) } int -pdf_get_crypt_length(pdf_document *xref) +pdf_crypt_length(pdf_document *xref) { if (xref->crypt) return xref->crypt->length; @@ -697,18 +707,18 @@ pdf_compute_object_key(pdf_crypt *crypt, pdf_crypt_filter *cf, int num, int gen, */ static void -pdf_crypt_obj_imp(fz_context *ctx, pdf_crypt *crypt, fz_obj *obj, unsigned char *key, int keylen) +pdf_crypt_obj_imp(fz_context *ctx, pdf_crypt *crypt, pdf_obj *obj, unsigned char *key, int keylen) { unsigned char *s; int i, n; - if (fz_is_indirect(obj)) + if (pdf_is_indirect(obj)) return; - if (fz_is_string(obj)) + if (pdf_is_string(obj)) { - s = (unsigned char *)fz_to_str_buf(obj); - n = fz_to_str_len(obj); + s = (unsigned char *)pdf_to_str_buf(obj); + n = pdf_to_str_len(obj); if (crypt->strf.method == PDF_CRYPT_RC4) { @@ -736,32 +746,32 @@ pdf_crypt_obj_imp(fz_context *ctx, pdf_crypt *crypt, fz_obj *obj, unsigned char if (s[n - 17] < 1 || s[n - 17] > 16) fz_warn(ctx, "aes padding out of range"); else - fz_set_str_len(obj, n - 16 - s[n - 17]); + pdf_set_str_len(obj, n - 16 - s[n - 17]); } } } - else if (fz_is_array(obj)) + else if (pdf_is_array(obj)) { - n = fz_array_len(obj); + n = pdf_array_len(obj); for (i = 0; i < n; i++) { - pdf_crypt_obj_imp(ctx, crypt, fz_array_get(obj, i), key, keylen); + pdf_crypt_obj_imp(ctx, crypt, pdf_array_get(obj, i), key, keylen); } } - else if (fz_is_dict(obj)) + else if (pdf_is_dict(obj)) { - n = fz_dict_len(obj); + n = pdf_dict_len(obj); for (i = 0; i < n; i++) { - pdf_crypt_obj_imp(ctx, crypt, fz_dict_get_val(obj, i), key, keylen); + pdf_crypt_obj_imp(ctx, crypt, pdf_dict_get_val(obj, i), key, keylen); } } } void -pdf_crypt_obj(fz_context *ctx, pdf_crypt *crypt, fz_obj *obj, int num, int gen) +pdf_crypt_obj(fz_context *ctx, pdf_crypt *crypt, pdf_obj *obj, int num, int gen) { unsigned char key[32]; int len; @@ -812,7 +822,7 @@ pdf_open_crypt_with_filter(fz_stream *chain, pdf_crypt *crypt, char *name, int n return chain; } -void pdf_debug_crypt(pdf_crypt *crypt) +void pdf_print_crypt(pdf_crypt *crypt) { int i; diff --git a/pdf/pdf_encoding.c b/pdf/pdf_encoding.c index 9a42a1c1..eb36ed96 100644 --- a/pdf/pdf_encoding.c +++ b/pdf/pdf_encoding.c @@ -1,5 +1,5 @@ -#include "fitz.h" -#include "mupdf.h" +#include "fitz-internal.h" +#include "mupdf-internal.h" #include "data_encodings.h" #include "data_glyphlist.h" diff --git a/pdf/pdf_font.c b/pdf/pdf_font.c index 3e30c332..ab60af72 100644 --- a/pdf/pdf_font.c +++ b/pdf/pdf_font.c @@ -1,11 +1,11 @@ -#include "fitz.h" -#include "mupdf.h" +#include "fitz-internal.h" +#include "mupdf-internal.h" #include <ft2build.h> #include FT_FREETYPE_H #include FT_XFREE86_H -static void pdf_load_font_descriptor(pdf_font_desc *fontdesc, pdf_document *xref, fz_obj *dict, char *collection, char *basefont); +static void pdf_load_font_descriptor(pdf_font_desc *fontdesc, pdf_document *xref, pdf_obj *dict, char *collection, char *basefont); static char *base_font_names[14][7] = { @@ -178,7 +178,7 @@ pdf_load_builtin_font(fz_context *ctx, pdf_font_desc *fontdesc, char *fontname) unsigned char *data; unsigned int len; - data = pdf_find_builtin_font(fontname, &len); + data = pdf_lookup_builtin_font(fontname, &len); if (!data) fz_throw(ctx, "cannot find builtin font: '%s'", fontname); @@ -195,7 +195,7 @@ pdf_load_substitute_font(fz_context *ctx, pdf_font_desc *fontdesc, int mono, int unsigned char *data; unsigned int len; - data = pdf_find_substitute_font(mono, serif, bold, italic, &len); + data = pdf_lookup_substitute_font(mono, serif, bold, italic, &len); if (!data) fz_throw(ctx, "cannot find substitute font"); @@ -213,7 +213,7 @@ pdf_load_substitute_cjk_font(fz_context *ctx, pdf_font_desc *fontdesc, int ros, unsigned char *data; unsigned int len; - data = pdf_find_substitute_cjk_font(ros, serif, &len); + data = pdf_lookup_substitute_cjk_font(ros, serif, &len); if (!data) fz_throw(ctx, "cannot find builtin CJK font"); @@ -268,18 +268,18 @@ pdf_load_system_font(fz_context *ctx, pdf_font_desc *fontdesc, char *fontname, c } static void -pdf_load_embedded_font(pdf_font_desc *fontdesc, pdf_document *xref, fz_obj *stmref) +pdf_load_embedded_font(pdf_font_desc *fontdesc, pdf_document *xref, pdf_obj *stmref) { fz_buffer *buf; fz_context *ctx = xref->ctx; fz_try(ctx) { - buf = pdf_load_stream(xref, fz_to_num(stmref), fz_to_gen(stmref)); + buf = pdf_load_stream(xref, pdf_to_num(stmref), pdf_to_gen(stmref)); } fz_catch(ctx) { - fz_throw(ctx, "cannot load font stream (%d %d R)", fz_to_num(stmref), fz_to_gen(stmref)); + fz_throw(ctx, "cannot load font stream (%d %d R)", pdf_to_num(stmref), pdf_to_gen(stmref)); } fz_try(ctx) @@ -289,7 +289,7 @@ pdf_load_embedded_font(pdf_font_desc *fontdesc, pdf_document *xref, fz_obj *stmr fz_catch(ctx) { fz_drop_buffer(ctx, buf); - fz_throw(ctx, "cannot load embedded font (%d %d R)", fz_to_num(stmref), fz_to_gen(stmref)); + fz_throw(ctx, "cannot load embedded font (%d %d R)", pdf_to_num(stmref), pdf_to_gen(stmref)); } fontdesc->size += buf->len; @@ -394,11 +394,11 @@ pdf_new_font_desc(fz_context *ctx) */ static pdf_font_desc * -pdf_load_simple_font(pdf_document *xref, fz_obj *dict) +pdf_load_simple_font(pdf_document *xref, pdf_obj *dict) { - fz_obj *descriptor; - fz_obj *encoding; - fz_obj *widths; + pdf_obj *descriptor; + pdf_obj *encoding; + pdf_obj *widths; unsigned short *etable = NULL; pdf_font_desc *fontdesc = NULL; FT_Face face; @@ -417,7 +417,7 @@ pdf_load_simple_font(pdf_document *xref, fz_obj *dict) fz_var(fontdesc); fz_var(etable); - basefont = fz_to_name(fz_dict_gets(dict, "BaseFont")); + basefont = pdf_to_name(pdf_dict_gets(dict, "BaseFont")); fontname = clean_font_name(basefont); /* Load font file */ @@ -425,7 +425,7 @@ pdf_load_simple_font(pdf_document *xref, fz_obj *dict) { fontdesc = pdf_new_font_desc(ctx); - descriptor = fz_dict_gets(dict, "FontDescriptor"); + descriptor = pdf_dict_gets(dict, "FontDescriptor"); if (descriptor) pdf_load_font_descriptor(fontdesc, xref, descriptor, NULL, basefont); else @@ -433,9 +433,9 @@ pdf_load_simple_font(pdf_document *xref, fz_obj *dict) /* Some chinese documents mistakenly consider WinAnsiEncoding to be codepage 936 */ if (!*fontdesc->font->name && - !fz_dict_gets(dict, "ToUnicode") && - !strcmp(fz_to_name(fz_dict_gets(dict, "Encoding")), "WinAnsiEncoding") && - fz_to_int(fz_dict_gets(descriptor, "Flags")) == 4) + !pdf_dict_gets(dict, "ToUnicode") && + !strcmp(pdf_to_name(pdf_dict_gets(dict, "Encoding")), "WinAnsiEncoding") && + pdf_to_int(pdf_dict_gets(descriptor, "Flags")) == 4) { /* note: without the comma, pdf_load_font_descriptor would prefer /FontName over /BaseFont */ char *cp936fonts[] = { @@ -514,34 +514,34 @@ pdf_load_simple_font(pdf_document *xref, fz_obj *dict) etable[i] = 0; } - encoding = fz_dict_gets(dict, "Encoding"); + encoding = pdf_dict_gets(dict, "Encoding"); if (encoding) { - if (fz_is_name(encoding)) - pdf_load_encoding(estrings, fz_to_name(encoding)); + if (pdf_is_name(encoding)) + pdf_load_encoding(estrings, pdf_to_name(encoding)); - if (fz_is_dict(encoding)) + if (pdf_is_dict(encoding)) { - fz_obj *base, *diff, *item; + pdf_obj *base, *diff, *item; - base = fz_dict_gets(encoding, "BaseEncoding"); - if (fz_is_name(base)) - pdf_load_encoding(estrings, fz_to_name(base)); + base = pdf_dict_gets(encoding, "BaseEncoding"); + if (pdf_is_name(base)) + pdf_load_encoding(estrings, pdf_to_name(base)); else if (!fontdesc->is_embedded && !symbolic) pdf_load_encoding(estrings, "StandardEncoding"); - diff = fz_dict_gets(encoding, "Differences"); - if (fz_is_array(diff)) + diff = pdf_dict_gets(encoding, "Differences"); + if (pdf_is_array(diff)) { - n = fz_array_len(diff); + n = pdf_array_len(diff); k = 0; for (i = 0; i < n; i++) { - item = fz_array_get(diff, i); - if (fz_is_int(item)) - k = fz_to_int(item); - if (fz_is_name(item)) - estrings[k++] = fz_to_name(item); + item = pdf_array_get(diff, i); + if (pdf_is_int(item)) + k = pdf_to_int(item); + if (pdf_is_name(item)) + estrings[k++] = pdf_to_name(item); if (k < 0) k = 0; if (k > 255) k = 255; } @@ -654,7 +654,7 @@ pdf_load_simple_font(pdf_document *xref, fz_obj *dict) fontdesc->cid_to_gid_len = 256; fontdesc->cid_to_gid = etable; - pdf_load_to_unicode(xref, fontdesc, estrings, NULL, fz_dict_gets(dict, "ToUnicode")); + pdf_load_to_unicode(xref, fontdesc, estrings, NULL, pdf_dict_gets(dict, "ToUnicode")); /* RJW: "cannot load to_unicode" */ skip_encoding: @@ -663,20 +663,20 @@ pdf_load_simple_font(pdf_document *xref, fz_obj *dict) pdf_set_default_hmtx(ctx, fontdesc, fontdesc->missing_width); - widths = fz_dict_gets(dict, "Widths"); + widths = pdf_dict_gets(dict, "Widths"); if (widths) { int first, last; - first = fz_to_int(fz_dict_gets(dict, "FirstChar")); - last = fz_to_int(fz_dict_gets(dict, "LastChar")); + first = pdf_to_int(pdf_dict_gets(dict, "FirstChar")); + last = pdf_to_int(pdf_dict_gets(dict, "LastChar")); if (first < 0 || last > 255 || first > last) first = last = 0; for (i = 0; i < last - first + 1; i++) { - int wid = fz_to_int(fz_array_get(widths, i)); + int wid = pdf_to_int(pdf_array_get(widths, i)); pdf_add_hmtx(ctx, fontdesc, i + first, i + first, wid); } } @@ -700,7 +700,7 @@ pdf_load_simple_font(pdf_document *xref, fz_obj *dict) if (fontdesc && etable != fontdesc->cid_to_gid) fz_free(ctx, etable); pdf_drop_font(ctx, fontdesc); - fz_throw(ctx, "cannot load simple font (%d %d R)", fz_to_num(dict), fz_to_gen(dict)); + fz_throw(ctx, "cannot load simple font (%d %d R)", pdf_to_num(dict), pdf_to_gen(dict)); } return fontdesc; } @@ -710,17 +710,17 @@ pdf_load_simple_font(pdf_document *xref, fz_obj *dict) */ static pdf_font_desc * -load_cid_font(pdf_document *xref, fz_obj *dict, fz_obj *encoding, fz_obj *to_unicode) +load_cid_font(pdf_document *xref, pdf_obj *dict, pdf_obj *encoding, pdf_obj *to_unicode) { - fz_obj *widths; - fz_obj *descriptor; + pdf_obj *widths; + pdf_obj *descriptor; pdf_font_desc *fontdesc; FT_Face face; int kind; char collection[256]; char *basefont; int i, k, fterr; - fz_obj *obj; + pdf_obj *obj; int dw; fz_context *ctx = xref->ctx; @@ -730,28 +730,28 @@ load_cid_font(pdf_document *xref, fz_obj *dict, fz_obj *encoding, fz_obj *to_uni { /* Get font name and CID collection */ - basefont = fz_to_name(fz_dict_gets(dict, "BaseFont")); + basefont = pdf_to_name(pdf_dict_gets(dict, "BaseFont")); { - fz_obj *cidinfo; + pdf_obj *cidinfo; char tmpstr[64]; int tmplen; - cidinfo = fz_dict_gets(dict, "CIDSystemInfo"); + cidinfo = pdf_dict_gets(dict, "CIDSystemInfo"); if (!cidinfo) fz_throw(ctx, "cid font is missing info"); - obj = fz_dict_gets(cidinfo, "Registry"); - tmplen = MIN(sizeof tmpstr - 1, fz_to_str_len(obj)); - memcpy(tmpstr, fz_to_str_buf(obj), tmplen); + obj = pdf_dict_gets(cidinfo, "Registry"); + tmplen = MIN(sizeof tmpstr - 1, pdf_to_str_len(obj)); + memcpy(tmpstr, pdf_to_str_buf(obj), tmplen); tmpstr[tmplen] = '\0'; fz_strlcpy(collection, tmpstr, sizeof collection); fz_strlcat(collection, "-", sizeof collection); - obj = fz_dict_gets(cidinfo, "Ordering"); - tmplen = MIN(sizeof tmpstr - 1, fz_to_str_len(obj)); - memcpy(tmpstr, fz_to_str_buf(obj), tmplen); + obj = pdf_dict_gets(cidinfo, "Ordering"); + tmplen = MIN(sizeof tmpstr - 1, pdf_to_str_len(obj)); + memcpy(tmpstr, pdf_to_str_buf(obj), tmplen); tmpstr[tmplen] = '\0'; fz_strlcat(collection, tmpstr, sizeof collection); } @@ -760,7 +760,7 @@ load_cid_font(pdf_document *xref, fz_obj *dict, fz_obj *encoding, fz_obj *to_uni fontdesc = pdf_new_font_desc(ctx); - descriptor = fz_dict_gets(dict, "FontDescriptor"); + descriptor = pdf_dict_gets(dict, "FontDescriptor"); if (!descriptor) fz_throw(ctx, "syntaxerror: missing font descriptor"); pdf_load_font_descriptor(fontdesc, xref, descriptor, collection, basefont); @@ -770,16 +770,16 @@ load_cid_font(pdf_document *xref, fz_obj *dict, fz_obj *encoding, fz_obj *to_uni /* Encoding */ - if (fz_is_name(encoding)) + if (pdf_is_name(encoding)) { - if (!strcmp(fz_to_name(encoding), "Identity-H")) + if (!strcmp(pdf_to_name(encoding), "Identity-H")) fontdesc->encoding = pdf_new_identity_cmap(ctx, 0, 2); - else if (!strcmp(fz_to_name(encoding), "Identity-V")) + else if (!strcmp(pdf_to_name(encoding), "Identity-V")) fontdesc->encoding = pdf_new_identity_cmap(ctx, 1, 2); else - fontdesc->encoding = pdf_load_system_cmap(ctx, fz_to_name(encoding)); + fontdesc->encoding = pdf_load_system_cmap(ctx, pdf_to_name(encoding)); } - else if (fz_is_indirect(encoding)) + else if (pdf_is_indirect(encoding)) { fontdesc->encoding = pdf_load_embedded_cmap(xref, encoding); } @@ -789,18 +789,18 @@ load_cid_font(pdf_document *xref, fz_obj *dict, fz_obj *encoding, fz_obj *to_uni } fontdesc->size += pdf_cmap_size(ctx, fontdesc->encoding); - pdf_set_font_wmode(ctx, fontdesc, pdf_get_wmode(ctx, fontdesc->encoding)); + pdf_set_font_wmode(ctx, fontdesc, pdf_cmap_wmode(ctx, fontdesc->encoding)); if (kind == TRUETYPE) { - fz_obj *cidtogidmap; + pdf_obj *cidtogidmap; - cidtogidmap = fz_dict_gets(dict, "CIDToGIDMap"); - if (fz_is_indirect(cidtogidmap)) + cidtogidmap = pdf_dict_gets(dict, "CIDToGIDMap"); + if (pdf_is_indirect(cidtogidmap)) { fz_buffer *buf; - buf = pdf_load_stream(xref, fz_to_num(cidtogidmap), fz_to_gen(cidtogidmap)); + buf = pdf_load_stream(xref, pdf_to_num(cidtogidmap), pdf_to_gen(cidtogidmap)); fontdesc->cid_to_gid_len = (buf->len) / 2; fontdesc->cid_to_gid = fz_malloc_array(ctx, fontdesc->cid_to_gid_len, sizeof(unsigned short)); @@ -842,35 +842,35 @@ load_cid_font(pdf_document *xref, fz_obj *dict, fz_obj *encoding, fz_obj *to_uni /* Horizontal */ dw = 1000; - obj = fz_dict_gets(dict, "DW"); + obj = pdf_dict_gets(dict, "DW"); if (obj) - dw = fz_to_int(obj); + dw = pdf_to_int(obj); pdf_set_default_hmtx(ctx, fontdesc, dw); - widths = fz_dict_gets(dict, "W"); + widths = pdf_dict_gets(dict, "W"); if (widths) { int c0, c1, w, n, m; - n = fz_array_len(widths); + n = pdf_array_len(widths); for (i = 0; i < n; ) { - c0 = fz_to_int(fz_array_get(widths, i)); - obj = fz_array_get(widths, i + 1); - if (fz_is_array(obj)) + c0 = pdf_to_int(pdf_array_get(widths, i)); + obj = pdf_array_get(widths, i + 1); + if (pdf_is_array(obj)) { - m = fz_array_len(obj); + m = pdf_array_len(obj); for (k = 0; k < m; k++) { - w = fz_to_int(fz_array_get(obj, k)); + w = pdf_to_int(pdf_array_get(obj, k)); pdf_add_hmtx(ctx, fontdesc, c0 + k, c0 + k, w); } i += 2; } else { - c1 = fz_to_int(obj); - w = fz_to_int(fz_array_get(widths, i + 2)); + c1 = pdf_to_int(obj); + w = pdf_to_int(pdf_array_get(widths, i + 2)); pdf_add_hmtx(ctx, fontdesc, c0, c1, w); i += 3; } @@ -881,48 +881,48 @@ load_cid_font(pdf_document *xref, fz_obj *dict, fz_obj *encoding, fz_obj *to_uni /* Vertical */ - if (pdf_get_wmode(ctx, fontdesc->encoding) == 1) + if (pdf_cmap_wmode(ctx, fontdesc->encoding) == 1) { int dw2y = 880; int dw2w = -1000; - obj = fz_dict_gets(dict, "DW2"); + obj = pdf_dict_gets(dict, "DW2"); if (obj) { - dw2y = fz_to_int(fz_array_get(obj, 0)); - dw2w = fz_to_int(fz_array_get(obj, 1)); + dw2y = pdf_to_int(pdf_array_get(obj, 0)); + dw2w = pdf_to_int(pdf_array_get(obj, 1)); } pdf_set_default_vmtx(ctx, fontdesc, dw2y, dw2w); - widths = fz_dict_gets(dict, "W2"); + widths = pdf_dict_gets(dict, "W2"); if (widths) { int c0, c1, w, x, y, n; - n = fz_array_len(widths); + n = pdf_array_len(widths); for (i = 0; i < n; ) { - c0 = fz_to_int(fz_array_get(widths, i)); - obj = fz_array_get(widths, i + 1); - if (fz_is_array(obj)) + c0 = pdf_to_int(pdf_array_get(widths, i)); + obj = pdf_array_get(widths, i + 1); + if (pdf_is_array(obj)) { - int m = fz_array_len(obj); + int m = pdf_array_len(obj); for (k = 0; k * 3 < m; k ++) { - w = fz_to_int(fz_array_get(obj, k * 3 + 0)); - x = fz_to_int(fz_array_get(obj, k * 3 + 1)); - y = fz_to_int(fz_array_get(obj, k * 3 + 2)); + w = pdf_to_int(pdf_array_get(obj, k * 3 + 0)); + x = pdf_to_int(pdf_array_get(obj, k * 3 + 1)); + y = pdf_to_int(pdf_array_get(obj, k * 3 + 2)); pdf_add_vmtx(ctx, fontdesc, c0 + k, c0 + k, x, y, w); } i += 2; } else { - c1 = fz_to_int(obj); - w = fz_to_int(fz_array_get(widths, i + 2)); - x = fz_to_int(fz_array_get(widths, i + 3)); - y = fz_to_int(fz_array_get(widths, i + 4)); + c1 = pdf_to_int(obj); + w = pdf_to_int(pdf_array_get(widths, i + 2)); + x = pdf_to_int(pdf_array_get(widths, i + 3)); + y = pdf_to_int(pdf_array_get(widths, i + 4)); pdf_add_vmtx(ctx, fontdesc, c0, c1, x, y, w); i += 5; } @@ -935,38 +935,38 @@ load_cid_font(pdf_document *xref, fz_obj *dict, fz_obj *encoding, fz_obj *to_uni fz_catch(ctx) { pdf_drop_font(ctx, fontdesc); - fz_throw(ctx, "cannot load cid font (%d %d R)", fz_to_num(dict), fz_to_gen(dict)); + fz_throw(ctx, "cannot load cid font (%d %d R)", pdf_to_num(dict), pdf_to_gen(dict)); } return fontdesc; } static pdf_font_desc * -pdf_load_type0_font(pdf_document *xref, fz_obj *dict) +pdf_load_type0_font(pdf_document *xref, pdf_obj *dict) { - fz_obj *dfonts; - fz_obj *dfont; - fz_obj *subtype; - fz_obj *encoding; - fz_obj *to_unicode; + pdf_obj *dfonts; + pdf_obj *dfont; + pdf_obj *subtype; + pdf_obj *encoding; + pdf_obj *to_unicode; - dfonts = fz_dict_gets(dict, "DescendantFonts"); + dfonts = pdf_dict_gets(dict, "DescendantFonts"); if (!dfonts) fz_throw(xref->ctx, "cid font is missing descendant fonts"); - dfont = fz_array_get(dfonts, 0); + dfont = pdf_array_get(dfonts, 0); - subtype = fz_dict_gets(dfont, "Subtype"); - encoding = fz_dict_gets(dict, "Encoding"); - to_unicode = fz_dict_gets(dict, "ToUnicode"); + subtype = pdf_dict_gets(dfont, "Subtype"); + encoding = pdf_dict_gets(dict, "Encoding"); + to_unicode = pdf_dict_gets(dict, "ToUnicode"); - if (fz_is_name(subtype) && !strcmp(fz_to_name(subtype), "CIDFontType0")) + if (pdf_is_name(subtype) && !strcmp(pdf_to_name(subtype), "CIDFontType0")) return load_cid_font(xref, dfont, encoding, to_unicode); - else if (fz_is_name(subtype) && !strcmp(fz_to_name(subtype), "CIDFontType2")) + else if (pdf_is_name(subtype) && !strcmp(pdf_to_name(subtype), "CIDFontType2")) return load_cid_font(xref, dfont, encoding, to_unicode); else fz_throw(xref->ctx, "syntaxerror: unknown cid font type"); - /* RJW: "cannot load descendant font (%d %d R)", fz_to_num(dfont), fz_to_gen(dfont) */ + /* RJW: "cannot load descendant font (%d %d R)", pdf_to_num(dfont), pdf_to_gen(dfont) */ return NULL; /* Stupid MSVC */ } @@ -975,34 +975,34 @@ pdf_load_type0_font(pdf_document *xref, fz_obj *dict) */ static void -pdf_load_font_descriptor(pdf_font_desc *fontdesc, pdf_document *xref, fz_obj *dict, char *collection, char *basefont) +pdf_load_font_descriptor(pdf_font_desc *fontdesc, pdf_document *xref, pdf_obj *dict, char *collection, char *basefont) { - fz_obj *obj1, *obj2, *obj3, *obj; + pdf_obj *obj1, *obj2, *obj3, *obj; char *fontname; char *origname; FT_Face face; fz_context *ctx = xref->ctx; if (!strchr(basefont, ',') || strchr(basefont, '+')) - origname = fz_to_name(fz_dict_gets(dict, "FontName")); + origname = pdf_to_name(pdf_dict_gets(dict, "FontName")); else origname = basefont; fontname = clean_font_name(origname); - fontdesc->flags = fz_to_int(fz_dict_gets(dict, "Flags")); - fontdesc->italic_angle = fz_to_real(fz_dict_gets(dict, "ItalicAngle")); - fontdesc->ascent = fz_to_real(fz_dict_gets(dict, "Ascent")); - fontdesc->descent = fz_to_real(fz_dict_gets(dict, "Descent")); - fontdesc->cap_height = fz_to_real(fz_dict_gets(dict, "CapHeight")); - fontdesc->x_height = fz_to_real(fz_dict_gets(dict, "XHeight")); - fontdesc->missing_width = fz_to_real(fz_dict_gets(dict, "MissingWidth")); - - obj1 = fz_dict_gets(dict, "FontFile"); - obj2 = fz_dict_gets(dict, "FontFile2"); - obj3 = fz_dict_gets(dict, "FontFile3"); + fontdesc->flags = pdf_to_int(pdf_dict_gets(dict, "Flags")); + fontdesc->italic_angle = pdf_to_real(pdf_dict_gets(dict, "ItalicAngle")); + fontdesc->ascent = pdf_to_real(pdf_dict_gets(dict, "Ascent")); + fontdesc->descent = pdf_to_real(pdf_dict_gets(dict, "Descent")); + fontdesc->cap_height = pdf_to_real(pdf_dict_gets(dict, "CapHeight")); + fontdesc->x_height = pdf_to_real(pdf_dict_gets(dict, "XHeight")); + fontdesc->missing_width = pdf_to_real(pdf_dict_gets(dict, "MissingWidth")); + + obj1 = pdf_dict_gets(dict, "FontFile"); + obj2 = pdf_dict_gets(dict, "FontFile2"); + obj3 = pdf_dict_gets(dict, "FontFile3"); obj = obj1 ? obj1 : obj2 ? obj2 : obj3; - if (fz_is_indirect(obj)) + if (pdf_is_indirect(obj)) { fz_try(ctx) { @@ -1015,7 +1015,7 @@ pdf_load_font_descriptor(pdf_font_desc *fontdesc, pdf_document *xref, fz_obj *di pdf_load_builtin_font(ctx, fontdesc, fontname); else pdf_load_system_font(ctx, fontdesc, fontname, collection); - /* RJW: "cannot load font descriptor (%d %d R)", fz_to_num(dict), fz_to_gen(dict) */ + /* RJW: "cannot load font descriptor (%d %d R)", pdf_to_num(dict), pdf_to_gen(dict) */ } } else @@ -1024,7 +1024,7 @@ pdf_load_font_descriptor(pdf_font_desc *fontdesc, pdf_document *xref, fz_obj *di pdf_load_builtin_font(ctx, fontdesc, fontname); else pdf_load_system_font(ctx, fontdesc, fontname, collection); - /* RJW: "cannot load font descriptor (%d %d R)", fz_to_num(dict), fz_to_gen(dict) */ + /* RJW: "cannot load font descriptor (%d %d R)", pdf_to_num(dict), pdf_to_gen(dict) */ } fz_strlcpy(fontdesc->font->name, fontname, sizeof fontdesc->font->name); @@ -1073,22 +1073,22 @@ pdf_make_width_table(fz_context *ctx, pdf_font_desc *fontdesc) } pdf_font_desc * -pdf_load_font(pdf_document *xref, fz_obj *rdb, fz_obj *dict) +pdf_load_font(pdf_document *xref, pdf_obj *rdb, pdf_obj *dict) { char *subtype; - fz_obj *dfonts; - fz_obj *charprocs; + pdf_obj *dfonts; + pdf_obj *charprocs; fz_context *ctx = xref->ctx; pdf_font_desc *fontdesc; - if ((fontdesc = fz_find_item(ctx, pdf_free_font_imp, dict))) + if ((fontdesc = pdf_find_item(ctx, pdf_free_font_imp, dict))) { return fontdesc; } - subtype = fz_to_name(fz_dict_gets(dict, "Subtype")); - dfonts = fz_dict_gets(dict, "DescendantFonts"); - charprocs = fz_dict_gets(dict, "CharProcs"); + subtype = pdf_to_name(pdf_dict_gets(dict, "Subtype")); + dfonts = pdf_dict_gets(dict, "DescendantFonts"); + charprocs = pdf_dict_gets(dict, "CharProcs"); if (subtype && !strcmp(subtype, "Type0")) fontdesc = pdf_load_type0_font(xref, dict); @@ -1115,19 +1115,19 @@ pdf_load_font(pdf_document *xref, fz_obj *rdb, fz_obj *dict) fz_warn(ctx, "unknown font format, guessing type1 or truetype."); fontdesc = pdf_load_simple_font(xref, dict); } - /* RJW: "cannot load font (%d %d R)", fz_to_num(dict), fz_to_gen(dict) */ + /* RJW: "cannot load font (%d %d R)", pdf_to_num(dict), pdf_to_gen(dict) */ /* Save the widths to stretch non-CJK substitute fonts */ if (fontdesc->font->ft_substitute && !fontdesc->to_ttf_cmap) pdf_make_width_table(ctx, fontdesc); - fz_store_item(ctx, dict, fontdesc, fontdesc->size); + pdf_store_item(ctx, dict, fontdesc, fontdesc->size); return fontdesc; } void -pdf_debug_font(fz_context *ctx, pdf_font_desc *fontdesc) +pdf_print_font(fz_context *ctx, pdf_font_desc *fontdesc) { int i; diff --git a/pdf/pdf_fontfile.c b/pdf/pdf_fontfile.c index 543ce763..b67d8a32 100644 --- a/pdf/pdf_fontfile.c +++ b/pdf/pdf_fontfile.c @@ -1,5 +1,5 @@ -#include "fitz.h" -#include "mupdf.h" +#include "fitz-internal.h" +#include "mupdf-internal.h" #ifdef NOCJK #define NOCJKFONT @@ -16,7 +16,7 @@ #endif unsigned char * -pdf_find_builtin_font(char *name, unsigned int *len) +pdf_lookup_builtin_font(char *name, unsigned int *len) { if (!strcmp("Courier", name)) { *len = sizeof pdf_font_NimbusMonL_Regu; @@ -79,32 +79,32 @@ pdf_find_builtin_font(char *name, unsigned int *len) } unsigned char * -pdf_find_substitute_font(int mono, int serif, int bold, int italic, unsigned int *len) +pdf_lookup_substitute_font(int mono, int serif, int bold, int italic, unsigned int *len) { #ifdef NODROIDFONT if (mono) { if (bold) { - if (italic) return pdf_find_builtin_font("Courier-BoldOblique", len); - else return pdf_find_builtin_font("Courier-Bold", len); + if (italic) return pdf_lookup_builtin_font("Courier-BoldOblique", len); + else return pdf_lookup_builtin_font("Courier-Bold", len); } else { - if (italic) return pdf_find_builtin_font("Courier-Oblique", len); - else return pdf_find_builtin_font("Courier", len); + if (italic) return pdf_lookup_builtin_font("Courier-Oblique", len); + else return pdf_lookup_builtin_font("Courier", len); } } else if (serif) { if (bold) { - if (italic) return pdf_find_builtin_font("Times-BoldItalic", len); - else return pdf_find_builtin_font("Times-Bold", len); + if (italic) return pdf_lookup_builtin_font("Times-BoldItalic", len); + else return pdf_lookup_builtin_font("Times-Bold", len); } else { - if (italic) return pdf_find_builtin_font("Times-Italic", len); - else return pdf_find_builtin_font("Times-Roman", len); + if (italic) return pdf_lookup_builtin_font("Times-Italic", len); + else return pdf_lookup_builtin_font("Times-Roman", len); } } else { if (bold) { - if (italic) return pdf_find_builtin_font("Helvetica-BoldOblique", len); - else return pdf_find_builtin_font("Helvetica-Bold", len); + if (italic) return pdf_lookup_builtin_font("Helvetica-BoldOblique", len); + else return pdf_lookup_builtin_font("Helvetica-Bold", len); } else { - if (italic) return pdf_find_builtin_font("Helvetica-Oblique", len); - else return pdf_find_builtin_font("Helvetica", len); + if (italic) return pdf_lookup_builtin_font("Helvetica-Oblique", len); + else return pdf_lookup_builtin_font("Helvetica", len); } } #else @@ -119,7 +119,7 @@ pdf_find_substitute_font(int mono, int serif, int bold, int italic, unsigned int } unsigned char * -pdf_find_substitute_cjk_font(int ros, int serif, unsigned int *len) +pdf_lookup_substitute_cjk_font(int ros, int serif, unsigned int *len) { #ifndef NOCJKFONT *len = sizeof pdf_font_DroidSansFallback; diff --git a/pdf/pdf_function.c b/pdf/pdf_function.c index 23acc4db..e1c53beb 100644 --- a/pdf/pdf_function.c +++ b/pdf/pdf_function.c @@ -1,5 +1,5 @@ -#include "fitz.h" -#include "mupdf.h" +#include "fitz-internal.h" +#include "mupdf-internal.h" enum { @@ -203,7 +203,13 @@ ps_push_real(ps_stack *st, float n) if (!ps_overflow(st, 1)) { st->stack[st->sp].type = PS_REAL; - st->stack[st->sp].u.f = n; + if (isnan(n)) + { + /* Push 1.0, as it's a small known value that won't + cause a divide by 0. Same reason as in fz_atof. */ + n = 1.0; + } + st->stack[st->sp].u.f = CLAMP(n, -FLT_MAX, FLT_MAX); st->sp++; } } @@ -360,10 +366,10 @@ ps_run(fz_context *ctx, psobj *code, ps_stack *st, int pc) case PS_OP_BITSHIFT: i2 = ps_pop_int(st); i1 = ps_pop_int(st); - if (i2 > 0) + if (i2 > 0 && i2 < 8 * sizeof (i2)) ps_push_int(st, i1 << i2); - else if (i2 < 0) - ps_push_int(st, (int)((unsigned int)i1 >> i2)); + else if (i2 < 0 && i2 > -8 * (int)sizeof (i2)) + ps_push_int(st, (int)((unsigned int)i1 >> -i2)); else ps_push_int(st, i1); break; @@ -393,7 +399,10 @@ ps_run(fz_context *ctx, psobj *code, ps_stack *st, int pc) case PS_OP_DIV: r2 = ps_pop_real(st); r1 = ps_pop_real(st); - ps_push_real(st, r1 / r2); + if (fabsf(r2) < FLT_EPSILON) + ps_push_real(st, r1 / r2); + else + ps_push_real(st, DIV_BY_ZERO(r1, r2, -FLT_MAX, FLT_MAX)); break; case PS_OP_DUP: @@ -466,7 +475,10 @@ ps_run(fz_context *ctx, psobj *code, ps_stack *st, int pc) case PS_OP_IDIV: i2 = ps_pop_int(st); i1 = ps_pop_int(st); - ps_push_int(st, i1 / i2); + if (i2 != 0) + ps_push_int(st, i1 / i2); + else + ps_push_int(st, DIV_BY_ZERO(i1, i2, INT_MIN, INT_MAX)); break; case PS_OP_INDEX: @@ -512,7 +524,10 @@ ps_run(fz_context *ctx, psobj *code, ps_stack *st, int pc) case PS_OP_MOD: i2 = ps_pop_int(st); i1 = ps_pop_int(st); - ps_push_int(st, i1 % i2); + if (i2 != 0) + ps_push_int(st, i1 % i2); + else + ps_push_int(st, DIV_BY_ZERO(i1, i2, INT_MIN, INT_MAX)); break; case PS_OP_MUL: @@ -683,18 +698,18 @@ resize_code(fz_context *ctx, pdf_function *func, int newsize) static void parse_code(pdf_function *func, fz_stream *stream, int *codeptr) { - char buf[64]; - int len; + pdf_lexbuf buf; int tok; int opptr, elseptr, ifptr; int a, b, mid, cmp; fz_context *ctx = stream->ctx; - memset(buf, 0, sizeof(buf)); + buf.size = PDF_LEXBUF_SMALL; + memset(buf.scratch, 0, sizeof(buf.scratch)); while (1) { - tok = pdf_lex(stream, buf, sizeof buf, &len); + tok = pdf_lex(stream, &buf); /* RJW: "calculator function lexical error" */ switch(tok) @@ -705,7 +720,7 @@ parse_code(pdf_function *func, fz_stream *stream, int *codeptr) case PDF_TOK_INT: resize_code(ctx, func, *codeptr); func->u.p.code[*codeptr].type = PS_INT; - func->u.p.code[*codeptr].u.i = atoi(buf); + func->u.p.code[*codeptr].u.i = buf.i; ++*codeptr; break; @@ -726,7 +741,7 @@ parse_code(pdf_function *func, fz_stream *stream, int *codeptr) case PDF_TOK_REAL: resize_code(ctx, func, *codeptr); func->u.p.code[*codeptr].type = PS_REAL; - func->u.p.code[*codeptr].u.f = fz_atof(buf); + func->u.p.code[*codeptr].u.f = buf.f; ++*codeptr; break; @@ -740,7 +755,7 @@ parse_code(pdf_function *func, fz_stream *stream, int *codeptr) parse_code(func, stream, codeptr); /* RJW: "error in 'if' branch" */ - tok = pdf_lex(stream, buf, sizeof buf, &len); + tok = pdf_lex(stream, &buf); /* RJW: "calculator function syntax error" */ if (tok == PDF_TOK_OPEN_BRACE) @@ -749,7 +764,7 @@ parse_code(pdf_function *func, fz_stream *stream, int *codeptr) parse_code(func, stream, codeptr); /* RJW: "error in 'else' branch" */ - tok = pdf_lex(stream, buf, sizeof buf, &len); + tok = pdf_lex(stream, &buf); /* RJW: "calculator function syntax error" */ } else @@ -760,7 +775,7 @@ parse_code(pdf_function *func, fz_stream *stream, int *codeptr) if (tok != PDF_TOK_KEYWORD) fz_throw(ctx, "missing keyword in 'if-else' context"); - if (!strcmp(buf, "if")) + if (!strcmp(buf.scratch, "if")) { if (elseptr >= 0) fz_throw(ctx, "too many branches for 'if'"); @@ -771,7 +786,7 @@ parse_code(pdf_function *func, fz_stream *stream, int *codeptr) func->u.p.code[opptr+3].type = PS_BLOCK; func->u.p.code[opptr+3].u.block = *codeptr; } - else if (!strcmp(buf, "ifelse")) + else if (!strcmp(buf.scratch, "ifelse")) { if (elseptr < 0) fz_throw(ctx, "not enough branches for 'ifelse'"); @@ -786,7 +801,7 @@ parse_code(pdf_function *func, fz_stream *stream, int *codeptr) } else { - fz_throw(ctx, "unknown keyword in 'if-else' context: '%s'", buf); + fz_throw(ctx, "unknown keyword in 'if-else' context: '%s'", buf.scratch); } break; @@ -804,7 +819,7 @@ parse_code(pdf_function *func, fz_stream *stream, int *codeptr) while (b - a > 1) { mid = (a + b) / 2; - cmp = strcmp(buf, ps_op_names[mid]); + cmp = strcmp(buf.scratch, ps_op_names[mid]); if (cmp > 0) a = mid; else if (cmp < 0) @@ -813,7 +828,7 @@ parse_code(pdf_function *func, fz_stream *stream, int *codeptr) a = b = mid; } if (cmp != 0) - fz_throw(ctx, "unknown operator: '%s'", buf); + fz_throw(ctx, "unknown operator: '%s'", buf.scratch); resize_code(ctx, func, *codeptr); func->u.p.code[*codeptr].type = PS_OPERATOR; @@ -828,16 +843,17 @@ parse_code(pdf_function *func, fz_stream *stream, int *codeptr) } static void -load_postscript_func(pdf_function *func, pdf_document *xref, fz_obj *dict, int num, int gen) +load_postscript_func(pdf_function *func, pdf_document *xref, pdf_obj *dict, int num, int gen) { fz_stream *stream = NULL; int codeptr; - char buf[64]; + pdf_lexbuf buf; int tok; - int len; fz_context *ctx = xref->ctx; int locked = 0; + buf.size = PDF_LEXBUF_SMALL; + fz_var(stream); fz_var(locked); @@ -846,7 +862,7 @@ load_postscript_func(pdf_function *func, pdf_document *xref, fz_obj *dict, int n stream = pdf_open_stream(xref, num, gen); /* RJW: "cannot open calculator function stream" */ - tok = pdf_lex(stream, buf, sizeof buf, &len); + tok = pdf_lex(stream, &buf); if (tok != PDF_TOK_OPEN_BRACE) { fz_throw(ctx, "stream is not a calculator function"); @@ -899,37 +915,37 @@ eval_postscript_func(fz_context *ctx, pdf_function *func, float *in, float *out) */ static void -load_sample_func(pdf_function *func, pdf_document *xref, fz_obj *dict, int num, int gen) +load_sample_func(pdf_function *func, pdf_document *xref, pdf_obj *dict, int num, int gen) { fz_context *ctx = xref->ctx; fz_stream *stream; - fz_obj *obj; + pdf_obj *obj; int samplecount; int bps; int i; func->u.sa.samples = NULL; - obj = fz_dict_gets(dict, "Size"); - if (!fz_is_array(obj) || fz_array_len(obj) != func->m) + obj = pdf_dict_gets(dict, "Size"); + if (!pdf_is_array(obj) || pdf_array_len(obj) != func->m) fz_throw(ctx, "malformed /Size"); for (i = 0; i < func->m; i++) - func->u.sa.size[i] = fz_to_int(fz_array_get(obj, i)); + func->u.sa.size[i] = pdf_to_int(pdf_array_get(obj, i)); - obj = fz_dict_gets(dict, "BitsPerSample"); - if (!fz_is_int(obj)) + obj = pdf_dict_gets(dict, "BitsPerSample"); + if (!pdf_is_int(obj)) fz_throw(ctx, "malformed /BitsPerSample"); - func->u.sa.bps = bps = fz_to_int(obj); + func->u.sa.bps = bps = pdf_to_int(obj); - obj = fz_dict_gets(dict, "Encode"); - if (fz_is_array(obj)) + obj = pdf_dict_gets(dict, "Encode"); + if (pdf_is_array(obj)) { - if (fz_array_len(obj) != func->m * 2) + if (pdf_array_len(obj) != func->m * 2) fz_throw(ctx, "malformed /Encode"); for (i = 0; i < func->m; i++) { - func->u.sa.encode[i][0] = fz_to_real(fz_array_get(obj, i*2+0)); - func->u.sa.encode[i][1] = fz_to_real(fz_array_get(obj, i*2+1)); + func->u.sa.encode[i][0] = pdf_to_real(pdf_array_get(obj, i*2+0)); + func->u.sa.encode[i][1] = pdf_to_real(pdf_array_get(obj, i*2+1)); } } else @@ -941,15 +957,15 @@ load_sample_func(pdf_function *func, pdf_document *xref, fz_obj *dict, int num, } } - obj = fz_dict_gets(dict, "Decode"); - if (fz_is_array(obj)) + obj = pdf_dict_gets(dict, "Decode"); + if (pdf_is_array(obj)) { - if (fz_array_len(obj) != func->n * 2) + if (pdf_array_len(obj) != func->n * 2) fz_throw(ctx, "malformed /Decode"); for (i = 0; i < func->n; i++) { - func->u.sa.decode[i][0] = fz_to_real(fz_array_get(obj, i*2+0)); - func->u.sa.decode[i][1] = fz_to_real(fz_array_get(obj, i*2+1)); + func->u.sa.decode[i][0] = pdf_to_real(pdf_array_get(obj, i*2+0)); + func->u.sa.decode[i][1] = pdf_to_real(pdf_array_get(obj, i*2+1)); } } else @@ -1110,27 +1126,27 @@ eval_sample_func(fz_context *ctx, pdf_function *func, float *in, float *out) */ static void -load_exponential_func(fz_context *ctx, pdf_function *func, fz_obj *dict) +load_exponential_func(fz_context *ctx, pdf_function *func, pdf_obj *dict) { - fz_obj *obj; + pdf_obj *obj; int i; if (func->m != 1) fz_throw(ctx, "/Domain must be one dimension (%d)", func->m); - obj = fz_dict_gets(dict, "N"); - if (!fz_is_int(obj) && !fz_is_real(obj)) + obj = pdf_dict_gets(dict, "N"); + if (!pdf_is_int(obj) && !pdf_is_real(obj)) fz_throw(ctx, "malformed /N"); - func->u.e.n = fz_to_real(obj); + func->u.e.n = pdf_to_real(obj); - obj = fz_dict_gets(dict, "C0"); - if (fz_is_array(obj)) + obj = pdf_dict_gets(dict, "C0"); + if (pdf_is_array(obj)) { - func->n = fz_array_len(obj); + func->n = pdf_array_len(obj); if (func->n >= MAXN) fz_throw(ctx, "exponential function result array out of range"); for (i = 0; i < func->n; i++) - func->u.e.c0[i] = fz_to_real(fz_array_get(obj, i)); + func->u.e.c0[i] = pdf_to_real(pdf_array_get(obj, i)); } else { @@ -1138,13 +1154,13 @@ load_exponential_func(fz_context *ctx, pdf_function *func, fz_obj *dict) func->u.e.c0[0] = 0; } - obj = fz_dict_gets(dict, "C1"); - if (fz_is_array(obj)) + obj = pdf_dict_gets(dict, "C1"); + if (pdf_is_array(obj)) { - if (fz_array_len(obj) != func->n) + if (pdf_array_len(obj) != func->n) fz_throw(ctx, "/C1 must match /C0 length"); for (i = 0; i < func->n; i++) - func->u.e.c1[i] = fz_to_real(fz_array_get(obj, i)); + func->u.e.c1[i] = pdf_to_real(pdf_array_get(obj, i)); } else { @@ -1184,13 +1200,13 @@ eval_exponential_func(fz_context *ctx, pdf_function *func, float in, float *out) */ static void -load_stitching_func(pdf_function *func, pdf_document *xref, fz_obj *dict) +load_stitching_func(pdf_function *func, pdf_document *xref, pdf_obj *dict) { fz_context *ctx = xref->ctx; pdf_function **funcs; - fz_obj *obj; - fz_obj *sub; - fz_obj *num; + pdf_obj *obj; + pdf_obj *sub; + pdf_obj *num; int k; int i; @@ -1199,11 +1215,11 @@ load_stitching_func(pdf_function *func, pdf_document *xref, fz_obj *dict) if (func->m != 1) fz_throw(ctx, "/Domain must be one dimension (%d)", func->m); - obj = fz_dict_gets(dict, "Functions"); - if (!fz_is_array(obj)) + obj = pdf_dict_gets(dict, "Functions"); + if (!pdf_is_array(obj)) fz_throw(ctx, "stitching function has no input functions"); { - k = fz_array_len(obj); + k = pdf_array_len(obj); func->u.st.funcs = fz_malloc_array(ctx, k, sizeof(pdf_function*)); func->u.st.bounds = fz_malloc_array(ctx, k - 1, sizeof(float)); @@ -1212,9 +1228,9 @@ load_stitching_func(pdf_function *func, pdf_document *xref, fz_obj *dict) for (i = 0; i < k; i++) { - sub = fz_array_get(obj, i); + sub = pdf_array_get(obj, i); funcs[i] = pdf_load_function(xref, sub); - /* RJW: "cannot load sub function %d (%d %d R)", i, fz_to_num(sub), fz_to_gen(sub) */ + /* RJW: "cannot load sub function %d (%d %d R)", i, pdf_to_num(sub), pdf_to_gen(sub) */ if (funcs[i]->m != 1 || funcs[i]->n != funcs[0]->n) fz_throw(ctx, "sub function %d /Domain or /Range mismatch", i); func->size += pdf_function_size(funcs[i]); @@ -1227,19 +1243,19 @@ load_stitching_func(pdf_function *func, pdf_document *xref, fz_obj *dict) fz_throw(ctx, "sub function /Domain or /Range mismatch"); } - obj = fz_dict_gets(dict, "Bounds"); - if (!fz_is_array(obj)) + obj = pdf_dict_gets(dict, "Bounds"); + if (!pdf_is_array(obj)) fz_throw(ctx, "stitching function has no bounds"); { - if (fz_array_len(obj) != k - 1) + if (pdf_array_len(obj) != k - 1) fz_throw(ctx, "malformed /Bounds (wrong length)"); for (i = 0; i < k-1; i++) { - num = fz_array_get(obj, i); - if (!fz_is_int(num) && !fz_is_real(num)) + num = pdf_array_get(obj, i); + if (!pdf_is_int(num) && !pdf_is_real(num)) fz_throw(ctx, "malformed /Bounds (item not real)"); - func->u.st.bounds[i] = fz_to_real(num); + func->u.st.bounds[i] = pdf_to_real(num); if (i && func->u.st.bounds[i-1] > func->u.st.bounds[i]) fz_throw(ctx, "malformed /Bounds (item not monotonic)"); } @@ -1249,16 +1265,16 @@ load_stitching_func(pdf_function *func, pdf_document *xref, fz_obj *dict) fz_warn(ctx, "malformed shading function bounds (domain mismatch), proceeding anyway."); } - obj = fz_dict_gets(dict, "Encode"); - if (!fz_is_array(obj)) + obj = pdf_dict_gets(dict, "Encode"); + if (!pdf_is_array(obj)) fz_throw(ctx, "stitching function is missing encoding"); { - if (fz_array_len(obj) != k * 2) + if (pdf_array_len(obj) != k * 2) fz_throw(ctx, "malformed /Encode"); for (i = 0; i < k; i++) { - func->u.st.encode[i*2+0] = fz_to_real(fz_array_get(obj, i*2+0)); - func->u.st.encode[i*2+1] = fz_to_real(fz_array_get(obj, i*2+1)); + func->u.st.encode[i*2+0] = pdf_to_real(pdf_array_get(obj, i*2+0)); + func->u.st.encode[i*2+1] = pdf_to_real(pdf_array_get(obj, i*2+1)); } } } @@ -1355,14 +1371,14 @@ pdf_function_size(pdf_function *func) } pdf_function * -pdf_load_function(pdf_document *xref, fz_obj *dict) +pdf_load_function(pdf_document *xref, pdf_obj *dict) { fz_context *ctx = xref->ctx; pdf_function *func; - fz_obj *obj; + pdf_obj *obj; int i; - if ((func = fz_find_item(ctx, pdf_free_function_imp, dict))) + if ((func = pdf_find_item(ctx, pdf_free_function_imp, dict))) { return func; } @@ -1371,28 +1387,28 @@ pdf_load_function(pdf_document *xref, fz_obj *dict) FZ_INIT_STORABLE(func, 1, pdf_free_function_imp); func->size = sizeof(*func); - obj = fz_dict_gets(dict, "FunctionType"); - func->type = fz_to_int(obj); + obj = pdf_dict_gets(dict, "FunctionType"); + func->type = pdf_to_int(obj); /* required for all */ - obj = fz_dict_gets(dict, "Domain"); - func->m = fz_array_len(obj) / 2; + obj = pdf_dict_gets(dict, "Domain"); + func->m = pdf_array_len(obj) / 2; for (i = 0; i < func->m; i++) { - func->domain[i][0] = fz_to_real(fz_array_get(obj, i * 2 + 0)); - func->domain[i][1] = fz_to_real(fz_array_get(obj, i * 2 + 1)); + func->domain[i][0] = pdf_to_real(pdf_array_get(obj, i * 2 + 0)); + func->domain[i][1] = pdf_to_real(pdf_array_get(obj, i * 2 + 1)); } /* required for type0 and type4, optional otherwise */ - obj = fz_dict_gets(dict, "Range"); - if (fz_is_array(obj)) + obj = pdf_dict_gets(dict, "Range"); + if (pdf_is_array(obj)) { func->has_range = 1; - func->n = fz_array_len(obj) / 2; + func->n = pdf_array_len(obj) / 2; for (i = 0; i < func->n; i++) { - func->range[i][0] = fz_to_real(fz_array_get(obj, i * 2 + 0)); - func->range[i][1] = fz_to_real(fz_array_get(obj, i * 2 + 1)); + func->range[i][0] = pdf_to_real(pdf_array_get(obj, i * 2 + 0)); + func->range[i][1] = pdf_to_real(pdf_array_get(obj, i * 2 + 1)); } } else @@ -1412,7 +1428,7 @@ pdf_load_function(pdf_document *xref, fz_obj *dict) switch(func->type) { case SAMPLE: - load_sample_func(func, xref, dict, fz_to_num(dict), fz_to_gen(dict)); + load_sample_func(func, xref, dict, pdf_to_num(dict), pdf_to_gen(dict)); break; case EXPONENTIAL: @@ -1424,15 +1440,15 @@ pdf_load_function(pdf_document *xref, fz_obj *dict) break; case POSTSCRIPT: - load_postscript_func(func, xref, dict, fz_to_num(dict), fz_to_gen(dict)); + load_postscript_func(func, xref, dict, pdf_to_num(dict), pdf_to_gen(dict)); break; default: fz_free(ctx, func); - fz_throw(ctx, "unknown function type (%d %d R)", fz_to_num(dict), fz_to_gen(dict)); + fz_throw(ctx, "unknown function type (%d %d R)", pdf_to_num(dict), pdf_to_gen(dict)); } - fz_store_item(ctx, dict, func, func->size); + pdf_store_item(ctx, dict, func, func->size); } fz_catch(ctx) { @@ -1444,7 +1460,7 @@ pdf_load_function(pdf_document *xref, fz_obj *dict) type == STITCHING ? "stitching" : type == POSTSCRIPT ? "calculator" : "unknown", - fz_to_num(dict), fz_to_gen(dict)); + pdf_to_num(dict), pdf_to_gen(dict)); } return func; diff --git a/pdf/pdf_image.c b/pdf/pdf_image.c index 3aa26f08..17996a74 100644 --- a/pdf/pdf_image.c +++ b/pdf/pdf_image.c @@ -1,10 +1,15 @@ -#include "fitz.h" -#include "mupdf.h" +#include "fitz-internal.h" +#include "mupdf-internal.h" -/* TODO: store JPEG compressed samples */ -/* TODO: store flate compressed samples */ +typedef struct pdf_image_key_s pdf_image_key; -static fz_pixmap *pdf_load_jpx(pdf_document *xref, fz_obj *dict); +struct pdf_image_key_s { + int refs; + fz_image *image; + int factor; +}; + +static void pdf_load_jpx(pdf_document *xref, pdf_obj *dict, pdf_image *image); static void pdf_mask_color_key(fz_pixmap *pix, int n, int *colorkey) @@ -25,58 +30,304 @@ pdf_mask_color_key(fz_pixmap *pix, int n, int *colorkey) } } +static int +pdf_make_hash_image_key(fz_store_hash *hash, void *key_) +{ + pdf_image_key *key = (pdf_image_key *)key_; + + hash->u.pi.ptr = key->image; + hash->u.pi.i = key->factor; + return 1; +} + +static void * +pdf_keep_image_key(fz_context *ctx, void *key_) +{ + pdf_image_key *key = (pdf_image_key *)key_; + + fz_lock(ctx, FZ_LOCK_ALLOC); + key->refs++; + fz_unlock(ctx, FZ_LOCK_ALLOC); + + return (void *)key; +} + +static void +pdf_drop_image_key(fz_context *ctx, void *key_) +{ + pdf_image_key *key = (pdf_image_key *)key_; + int drop; + + fz_lock(ctx, FZ_LOCK_ALLOC); + drop = --key->refs; + fz_unlock(ctx, FZ_LOCK_ALLOC); + if (drop == 0) + { + fz_drop_image(ctx, key->image); + fz_free(ctx, key); + } +} + +static int +pdf_cmp_image_key(void *k0_, void *k1_) +{ + pdf_image_key *k0 = (pdf_image_key *)k0_; + pdf_image_key *k1 = (pdf_image_key *)k1_; + + return k0->image == k1->image && k0->factor == k1->factor; +} + +static void +pdf_debug_image(void *key_) +{ + pdf_image_key *key = (pdf_image_key *)key_; + + printf("(image %d x %d sf=%d) ", key->image->w, key->image->h, key->factor); +} + +static fz_store_type pdf_image_store_type = +{ + pdf_make_hash_image_key, + pdf_keep_image_key, + pdf_drop_image_key, + pdf_cmp_image_key, + pdf_debug_image +}; + static fz_pixmap * -pdf_load_image_imp(pdf_document *xref, fz_obj *rdb, fz_obj *dict, fz_stream *cstm, int forcemask) +decomp_image_from_stream(fz_context *ctx, fz_stream *stm, pdf_image *image, int in_line, int indexed, int factor) { - fz_stream *stm = NULL; fz_pixmap *tile = NULL; - fz_obj *obj, *res; + fz_pixmap *existing_tile; + int stride, len, i; + unsigned char *samples = NULL; + int w = (image->base.w + (factor-1)) / factor; + int h = (image->base.h + (factor-1)) / factor; + pdf_image_key *key; + + fz_var(tile); + fz_var(samples); + + fz_try(ctx) + { + tile = fz_new_pixmap(ctx, image->base.colorspace, w, h); + tile->interpolate = image->interpolate; + + stride = (w * image->n * image->bpc + 7) / 8; + + samples = fz_malloc_array(ctx, h, stride); + + len = fz_read(stm, samples, h * stride); + if (len < 0) + { + fz_throw(ctx, "cannot read image data"); + } + + /* Make sure we read the EOF marker (for inline images only) */ + if (in_line) + { + unsigned char tbuf[512]; + fz_try(ctx) + { + int tlen = fz_read(stm, tbuf, sizeof tbuf); + if (tlen > 0) + fz_warn(ctx, "ignoring garbage at end of image"); + } + fz_catch(ctx) + { + fz_warn(ctx, "ignoring error at end of image"); + } + } + + /* Pad truncated images */ + if (len < stride * h) + { + fz_warn(ctx, "padding truncated image"); + memset(samples + len, 0, stride * h - len); + } + + /* Invert 1-bit image masks */ + if (image->imagemask) + { + /* 0=opaque and 1=transparent so we need to invert */ + unsigned char *p = samples; + len = h * stride; + for (i = 0; i < len; i++) + p[i] = ~p[i]; + } + + fz_unpack_tile(tile, samples, image->n, image->bpc, stride, indexed); + + fz_free(ctx, samples); + samples = NULL; + + if (image->usecolorkey) + pdf_mask_color_key(tile, image->n, image->colorkey); + + if (indexed) + { + fz_pixmap *conv; + fz_decode_indexed_tile(tile, image->decode, (1 << image->bpc) - 1); + conv = pdf_expand_indexed_pixmap(ctx, tile); + fz_drop_pixmap(ctx, tile); + tile = conv; + } + else + { + fz_decode_tile(tile, image->decode); + } + } + fz_always(ctx) + { + fz_close(stm); + } + fz_catch(ctx) + { + if (tile) + fz_drop_pixmap(ctx, tile); + fz_free(ctx, samples); + + fz_rethrow(ctx); + } + + /* Now we try to cache the pixmap. Any failure here will just result + * in us not caching. */ + fz_try(ctx) + { + key = fz_malloc_struct(ctx, pdf_image_key); + key->refs = 1; + key->image = fz_keep_image(ctx, &image->base); + key->factor = factor; + existing_tile = fz_store_item(ctx, key, tile, fz_pixmap_size(ctx, tile), &pdf_image_store_type); + if (existing_tile) + { + /* We already have a tile. This must have been produced by a + * racing thread. We'll throw away ours and use that one. */ + fz_drop_pixmap(ctx, tile); + tile = existing_tile; + } + } + fz_always(ctx) + { + pdf_drop_image_key(ctx, key); + } + fz_catch(ctx) + { + /* Do nothing */ + } + + return tile; +} + +static void +pdf_free_image(fz_context *ctx, fz_storable *image_) +{ + pdf_image *image = (pdf_image *)image_; + + if (image == NULL) + return; + fz_drop_pixmap(ctx, image->tile); + fz_drop_buffer(ctx, image->buffer); + fz_drop_colorspace(ctx, image->base.colorspace); + fz_drop_image(ctx, image->base.mask); + fz_free(ctx, image); +} + +static fz_pixmap * +pdf_image_get_pixmap(fz_context *ctx, fz_image *image_, int w, int h) +{ + pdf_image *image = (pdf_image *)image_; + fz_pixmap *tile; + fz_stream *stm; + int factor; + pdf_image_key key; + + /* Check for 'simple' images which are just pixmaps */ + if (image->buffer == NULL) + { + tile = image->tile; + if (!tile) + return NULL; + return fz_keep_pixmap(ctx, tile); /* That's all we can give you! */ + } + + /* Ensure our expectations for tile size are reasonable */ + if (w > image->base.w) + w = image->base.w; + if (h > image->base.h) + h = image->base.h; + + /* What is our ideal factor? */ + if (w == 0 || h == 0) + factor = 1; + else + for (factor=1; image->base.w/(2*factor) >= w && image->base.h/(2*factor) >= h && factor < 8; factor *= 2); + + /* Can we find any suitable tiles in the cache? */ + key.refs = 1; + key.image = &image->base; + key.factor = factor; + do + { + tile = fz_find_item(ctx, fz_free_pixmap_imp, &key, &pdf_image_store_type); + if (tile) + return tile; + key.factor >>= 1; + } + while (key.factor > 0); + + /* We need to make a new one. */ + stm = pdf_open_image_decomp_stream(ctx, image->buffer, &image->params, &factor); + + return decomp_image_from_stream(ctx, stm, image, 0, 0, factor); +} + +static pdf_image * +pdf_load_image_imp(pdf_document *xref, pdf_obj *rdb, pdf_obj *dict, fz_stream *cstm, int forcemask) +{ + fz_stream *stm = NULL; + pdf_image *image = NULL; + pdf_obj *obj, *res; int w, h, bpc, n; int imagemask; int interpolate; int indexed; - fz_colorspace *colorspace = NULL; - fz_pixmap *mask = NULL; /* explicit mask/softmask image */ + fz_image *mask = NULL; /* explicit mask/softmask image */ int usecolorkey; - int colorkey[FZ_MAX_COLORS * 2]; - float decode[FZ_MAX_COLORS * 2]; - int stride; - unsigned char *samples = NULL; - int i, len; + int i; fz_context *ctx = xref->ctx; fz_var(stm); - fz_var(tile); - fz_var(colorspace); fz_var(mask); - fz_var(samples); + + image = fz_malloc_struct(ctx, pdf_image); fz_try(ctx) { /* special case for JPEG2000 images */ if (pdf_is_jpx_image(ctx, dict)) { - tile = pdf_load_jpx(xref, dict); + pdf_load_jpx(xref, dict, image); /* RJW: "cannot load jpx image" */ if (forcemask) { - if (tile->n != 2) + fz_pixmap *mask_pixmap; + if (image->n != 2) fz_throw(ctx, "softmask must be grayscale"); - mask = fz_alpha_from_gray(ctx, tile, 1); - fz_drop_pixmap(ctx, tile); - tile = mask; - mask = NULL; + mask_pixmap = fz_alpha_from_gray(ctx, image->tile, 1); + fz_drop_pixmap(ctx, image->tile); + image->tile = mask_pixmap; } break; /* Out of fz_try */ } - w = fz_to_int(fz_dict_getsa(dict, "Width", "W")); - h = fz_to_int(fz_dict_getsa(dict, "Height", "H")); - bpc = fz_to_int(fz_dict_getsa(dict, "BitsPerComponent", "BPC")); - imagemask = fz_to_bool(fz_dict_getsa(dict, "ImageMask", "IM")); - interpolate = fz_to_bool(fz_dict_getsa(dict, "Interpolate", "I")); + w = pdf_to_int(pdf_dict_getsa(dict, "Width", "W")); + h = pdf_to_int(pdf_dict_getsa(dict, "Height", "H")); + bpc = pdf_to_int(pdf_dict_getsa(dict, "BitsPerComponent", "BPC")); + imagemask = pdf_to_bool(pdf_dict_getsa(dict, "ImageMask", "IM")); + interpolate = pdf_to_bool(pdf_dict_getsa(dict, "Interpolate", "I")); indexed = 0; usecolorkey = 0; @@ -98,212 +349,140 @@ pdf_load_image_imp(pdf_document *xref, fz_obj *rdb, fz_obj *dict, fz_stream *cst if (h > (1 << 16)) fz_throw(ctx, "image is too high"); - obj = fz_dict_getsa(dict, "ColorSpace", "CS"); + obj = pdf_dict_getsa(dict, "ColorSpace", "CS"); if (obj && !imagemask && !forcemask) { /* colorspace resource lookup is only done for inline images */ - if (fz_is_name(obj)) + if (pdf_is_name(obj)) { - res = fz_dict_get(fz_dict_gets(rdb, "ColorSpace"), obj); + res = pdf_dict_get(pdf_dict_gets(rdb, "ColorSpace"), obj); if (res) obj = res; } - colorspace = pdf_load_colorspace(xref, obj); + image->base.colorspace = pdf_load_colorspace(xref, obj); /* RJW: "cannot load image colorspace" */ - if (!strcmp(colorspace->name, "Indexed")) + if (!strcmp(image->base.colorspace->name, "Indexed")) indexed = 1; - n = colorspace->n; + n = image->base.colorspace->n; } else { n = 1; } - obj = fz_dict_getsa(dict, "Decode", "D"); + obj = pdf_dict_getsa(dict, "Decode", "D"); if (obj) { for (i = 0; i < n * 2; i++) - decode[i] = fz_to_real(fz_array_get(obj, i)); + image->decode[i] = pdf_to_real(pdf_array_get(obj, i)); } else { float maxval = indexed ? (1 << bpc) - 1 : 1; for (i = 0; i < n * 2; i++) - decode[i] = i & 1 ? maxval : 0; + image->decode[i] = i & 1 ? maxval : 0; } - obj = fz_dict_getsa(dict, "SMask", "Mask"); - if (fz_is_dict(obj)) + obj = pdf_dict_getsa(dict, "SMask", "Mask"); + if (pdf_is_dict(obj)) { /* Not allowed for inline images */ if (!cstm) { - mask = pdf_load_image_imp(xref, rdb, obj, NULL, 1); + mask = (fz_image *)pdf_load_image_imp(xref, rdb, obj, NULL, 1); /* RJW: "cannot load image mask/softmask" */ } } - else if (fz_is_array(obj)) + else if (pdf_is_array(obj)) { usecolorkey = 1; for (i = 0; i < n * 2; i++) { - if (!fz_is_int(fz_array_get(obj, i))) + if (!pdf_is_int(pdf_array_get(obj, i))) { fz_warn(ctx, "invalid value in color key mask"); usecolorkey = 0; } - colorkey[i] = fz_to_int(fz_array_get(obj, i)); + image->colorkey[i] = pdf_to_int(pdf_array_get(obj, i)); } } - /* Allocate now, to fail early if we run out of memory */ - fz_try(ctx) - { - tile = fz_new_pixmap(ctx, colorspace, w, h); - } - fz_catch(ctx) - { - fz_drop_colorspace(ctx, colorspace); - fz_rethrow(ctx); - } - - if (colorspace) + /* Now, do we load a ref, or do we load the actual thing? */ + image->params.type = PDF_IMAGE_RAW; + FZ_INIT_STORABLE(&image->base, 1, pdf_free_image); + image->base.get_pixmap = pdf_image_get_pixmap; + image->base.w = w; + image->base.h = h; + image->n = n; + image->bpc = bpc; + image->interpolate = interpolate; + image->imagemask = imagemask; + image->usecolorkey = usecolorkey; + image->base.mask = mask; + image->params.colorspace = image->base.colorspace; /* Uses the same ref as for the base one */ + if (!indexed && !cstm) { - fz_drop_colorspace(ctx, colorspace); - colorspace = NULL; + /* Just load the compressed image data now and we can + * decode it on demand. */ + image->buffer = pdf_load_image_stream(xref, pdf_to_num(dict), pdf_to_gen(dict), &image->params); + break; /* Out of fz_try */ } - tile->mask = mask; - mask = NULL; - tile->interpolate = interpolate; - - stride = (w * n * bpc + 7) / 8; - + /* We need to decompress the image now */ if (cstm) { - stm = pdf_open_inline_stream(xref, dict, stride * h, cstm); + int stride = (w * image->n * image->bpc + 7) / 8; + stm = pdf_open_inline_stream(xref, dict, stride * h, cstm, NULL); } else { - stm = pdf_open_stream(xref, fz_to_num(dict), fz_to_gen(dict)); - /* RJW: "cannot open image data stream (%d 0 R)", fz_to_num(dict) */ - } - - samples = fz_malloc_array(ctx, h, stride); - - len = fz_read(stm, samples, h * stride); - if (len < 0) - { - fz_throw(ctx, "cannot read image data"); - } - - /* Make sure we read the EOF marker (for inline images only) */ - if (cstm) - { - unsigned char tbuf[512]; - fz_try(ctx) - { - int tlen = fz_read(stm, tbuf, sizeof tbuf); - if (tlen > 0) - fz_warn(ctx, "ignoring garbage at end of image"); - } - fz_catch(ctx) - { - fz_warn(ctx, "ignoring error at end of image"); - } - } - - fz_close(stm); - stm = NULL; - - /* Pad truncated images */ - if (len < stride * h) - { - fz_warn(ctx, "padding truncated image (%d 0 R)", fz_to_num(dict)); - memset(samples + len, 0, stride * h - len); + stm = pdf_open_stream(xref, pdf_to_num(dict), pdf_to_gen(dict)); + /* RJW: "cannot open image data stream (%d 0 R)", pdf_to_num(dict) */ } - /* Invert 1-bit image masks */ - if (imagemask) - { - /* 0=opaque and 1=transparent so we need to invert */ - unsigned char *p = samples; - len = h * stride; - for (i = 0; i < len; i++) - p[i] = ~p[i]; - } - - fz_unpack_tile(tile, samples, n, bpc, stride, indexed); - - fz_free(ctx, samples); - samples = NULL; - - if (usecolorkey) - pdf_mask_color_key(tile, n, colorkey); - - if (indexed) - { - fz_pixmap *conv; - fz_decode_indexed_tile(tile, decode, (1 << bpc) - 1); - conv = pdf_expand_indexed_pixmap(ctx, tile); - fz_drop_pixmap(ctx, tile); - tile = conv; - } - else - { - fz_decode_tile(tile, decode); - } + image->tile = decomp_image_from_stream(ctx, stm, image, cstm != NULL, indexed, 1); } fz_catch(ctx) { - if (colorspace) - fz_drop_colorspace(ctx, colorspace); - if (mask) - fz_drop_pixmap(ctx, mask); - if (tile) - fz_drop_pixmap(ctx, tile); - fz_close(stm); - fz_free(ctx, samples); - + fz_drop_image(ctx, &image->base); fz_rethrow(ctx); } - - return tile; + return image; } -fz_pixmap * -pdf_load_inline_image(pdf_document *xref, fz_obj *rdb, fz_obj *dict, fz_stream *file) +fz_image * +pdf_load_inline_image(pdf_document *xref, pdf_obj *rdb, pdf_obj *dict, fz_stream *file) { - return pdf_load_image_imp(xref, rdb, dict, file, 0); + return (fz_image *)pdf_load_image_imp(xref, rdb, dict, file, 0); /* RJW: "cannot load inline image" */ } int -pdf_is_jpx_image(fz_context *ctx, fz_obj *dict) +pdf_is_jpx_image(fz_context *ctx, pdf_obj *dict) { - fz_obj *filter; + pdf_obj *filter; int i, n; - filter = fz_dict_gets(dict, "Filter"); - if (!strcmp(fz_to_name(filter), "JPXDecode")) + filter = pdf_dict_gets(dict, "Filter"); + if (!strcmp(pdf_to_name(filter), "JPXDecode")) return 1; - n = fz_array_len(filter); + n = pdf_array_len(filter); for (i = 0; i < n; i++) - if (!strcmp(fz_to_name(fz_array_get(filter, i)), "JPXDecode")) + if (!strcmp(pdf_to_name(pdf_array_get(filter, i)), "JPXDecode")) return 1; return 0; } -static fz_pixmap * -pdf_load_jpx(pdf_document *xref, fz_obj *dict) +static void +pdf_load_jpx(pdf_document *xref, pdf_obj *dict, pdf_image *image) { fz_buffer *buf = NULL; fz_colorspace *colorspace = NULL; fz_pixmap *img = NULL; - fz_obj *obj; + pdf_obj *obj; fz_context *ctx = xref->ctx; int indexed = 0; @@ -311,13 +490,13 @@ pdf_load_jpx(pdf_document *xref, fz_obj *dict) fz_var(buf); fz_var(colorspace); - buf = pdf_load_stream(xref, fz_to_num(dict), fz_to_gen(dict)); + buf = pdf_load_stream(xref, pdf_to_num(dict), pdf_to_gen(dict)); /* RJW: "cannot load jpx image data" */ /* FIXME: We can't handle decode arrays for indexed images currently */ fz_try(ctx) { - obj = fz_dict_gets(dict, "ColorSpace"); + obj = pdf_dict_gets(dict, "ColorSpace"); if (obj) { colorspace = pdf_load_colorspace(xref, obj); @@ -328,29 +507,27 @@ pdf_load_jpx(pdf_document *xref, fz_obj *dict) img = fz_load_jpx(ctx, buf->data, buf->len, colorspace); /* RJW: "cannot load jpx image" */ - if (colorspace) - { - fz_drop_colorspace(ctx, colorspace); - colorspace = NULL; - } + if (img && colorspace == NULL) + colorspace = fz_keep_colorspace(ctx, img->colorspace); + fz_drop_buffer(ctx, buf); buf = NULL; - obj = fz_dict_getsa(dict, "SMask", "Mask"); - if (fz_is_dict(obj)) + obj = pdf_dict_getsa(dict, "SMask", "Mask"); + if (pdf_is_dict(obj)) { - img->mask = pdf_load_image_imp(xref, NULL, obj, NULL, 1); + image->base.mask = (fz_image *)pdf_load_image_imp(xref, NULL, obj, NULL, 1); /* RJW: "cannot load image mask/softmask" */ } - obj = fz_dict_getsa(dict, "Decode", "D"); + obj = pdf_dict_getsa(dict, "Decode", "D"); if (obj && !indexed) { float decode[FZ_MAX_COLORS * 2]; int i; for (i = 0; i < img->n * 2; i++) - decode[i] = fz_to_real(fz_array_get(obj, i)); + decode[i] = pdf_to_real(pdf_array_get(obj, i)); fz_decode_tile(img, decode); } @@ -363,24 +540,44 @@ pdf_load_jpx(pdf_document *xref, fz_obj *dict) fz_drop_pixmap(ctx, img); fz_rethrow(ctx); } - return img; + image->params.type = PDF_IMAGE_RAW; + FZ_INIT_STORABLE(&image->base, 1, pdf_free_image); + image->base.get_pixmap = pdf_image_get_pixmap; + image->base.w = img->w; + image->base.h = img->h; + image->base.colorspace = colorspace; + image->tile = img; + image->n = img->n; + image->bpc = 8; + image->interpolate = 0; + image->imagemask = 0; + image->usecolorkey = 0; + image->params.colorspace = colorspace; /* Uses the same ref as for the base one */ +} + +static int +pdf_image_size(fz_context *ctx, pdf_image *im) +{ + if (im == NULL) + return 0; + return sizeof(*im) + fz_pixmap_size(ctx, im->tile) + (im->buffer ? im->buffer->cap : 0); } -fz_pixmap * -pdf_load_image(pdf_document *xref, fz_obj *dict) +fz_image * +pdf_load_image(pdf_document *xref, pdf_obj *dict) { fz_context *ctx = xref->ctx; - fz_pixmap *pix; + pdf_image *image; - if ((pix = fz_find_item(ctx, fz_free_pixmap_imp, dict))) + if ((image = pdf_find_item(ctx, pdf_free_image, dict))) { - return pix; + return (fz_image *)image; } - pix = pdf_load_image_imp(xref, NULL, dict, NULL, 0); - /* RJW: "cannot load image (%d 0 R)", fz_to_num(dict) */ + image = pdf_load_image_imp(xref, NULL, dict, NULL, 0); + /* RJW: "cannot load image (%d 0 R)", pdf_to_num(dict) */ - fz_store_item(ctx, dict, pix, fz_pixmap_size(ctx, pix)); + pdf_store_item(ctx, dict, image, pdf_image_size(ctx, image)); - return pix; + return (fz_image *)image; } diff --git a/pdf/pdf_interpret.c b/pdf/pdf_interpret.c index ea7f7692..3888b35f 100644 --- a/pdf/pdf_interpret.c +++ b/pdf/pdf_interpret.c @@ -1,5 +1,5 @@ -#include "fitz.h" -#include "mupdf.h" +#include "fitz-internal.h" +#include "mupdf-internal.h" #define TILE @@ -70,7 +70,7 @@ struct pdf_csi_s char *event; /* "View", "Print", "Export" */ /* interpreter stack */ - fz_obj *obj; + pdf_obj *obj; char name[256]; unsigned char string[256]; int string_len; @@ -104,8 +104,8 @@ struct pdf_csi_s fz_cookie *cookie; }; -static void pdf_run_buffer(pdf_csi *csi, fz_obj *rdb, fz_buffer *contents); -static void pdf_run_xobject(pdf_csi *csi, fz_obj *resources, pdf_xobject *xobj, fz_matrix transform); +static void pdf_run_buffer(pdf_csi *csi, pdf_obj *rdb, fz_buffer *contents); +static void pdf_run_xobject(pdf_csi *csi, pdf_obj *resources, pdf_xobject *xobj, fz_matrix transform); static void pdf_show_pattern(pdf_csi *csi, pdf_pattern *pat, fz_rect area, int what); static int @@ -120,20 +120,20 @@ ocg_intents_include(pdf_ocg_descriptor *desc, char *name) if (!desc->intent) return (strcmp(name, "View") == 0); - if (fz_is_name(desc->intent)) + if (pdf_is_name(desc->intent)) { - char *intent = fz_to_name(desc->intent); + char *intent = pdf_to_name(desc->intent); if (strcmp(intent, "All") == 0) return 1; return (strcmp(intent, name) == 0); } - if (!fz_is_array(desc->intent)) + if (!pdf_is_array(desc->intent)) return 0; - len = fz_array_len(desc->intent); + len = pdf_array_len(desc->intent); for (i=0; i < len; i++) { - char *intent = fz_to_name(fz_array_get(desc->intent, i)); + char *intent = pdf_to_name(pdf_array_get(desc->intent, i)); if (strcmp(intent, "All") == 0) return 1; if (strcmp(intent, name) == 0) @@ -143,10 +143,10 @@ ocg_intents_include(pdf_ocg_descriptor *desc, char *name) } static int -pdf_is_hidden_ocg(fz_obj *ocg, pdf_csi *csi, fz_obj *rdb) +pdf_is_hidden_ocg(pdf_obj *ocg, pdf_csi *csi, pdf_obj *rdb) { char event_state[16]; - fz_obj *obj, *obj2; + pdf_obj *obj, *obj2; char *type; pdf_ocg_descriptor *desc = csi->xref->ocg; @@ -155,9 +155,9 @@ pdf_is_hidden_ocg(fz_obj *ocg, pdf_csi *csi, fz_obj *rdb) return 0; /* If we've been handed a name, look it up in the properties. */ - if (fz_is_name(ocg)) + if (pdf_is_name(ocg)) { - ocg = fz_dict_gets(fz_dict_gets(rdb, "Properties"), fz_to_name(ocg)); + ocg = pdf_dict_gets(pdf_dict_gets(rdb, "Properties"), pdf_to_name(ocg)); } /* If we haven't been given an ocg at all, then we're visible */ if (!ocg) @@ -166,13 +166,13 @@ pdf_is_hidden_ocg(fz_obj *ocg, pdf_csi *csi, fz_obj *rdb) fz_strlcpy(event_state, csi->event, sizeof event_state); fz_strlcat(event_state, "State", sizeof event_state); - type = fz_to_name(fz_dict_gets(ocg, "Type")); + type = pdf_to_name(pdf_dict_gets(ocg, "Type")); if (strcmp(type, "OCG") == 0) { /* An Optional Content Group */ - int num = fz_to_num(ocg); - int gen = fz_to_gen(ocg); + int num = pdf_to_num(ocg); + int gen = pdf_to_gen(ocg); int len = desc->len; int i; @@ -188,19 +188,19 @@ pdf_is_hidden_ocg(fz_obj *ocg, pdf_csi *csi, fz_obj *rdb) /* Check Intents; if our intent is not part of the set given * by the current config, we should ignore it. */ - obj = fz_dict_gets(ocg, "Intent"); - if (fz_is_name(obj)) + obj = pdf_dict_gets(ocg, "Intent"); + if (pdf_is_name(obj)) { /* If it doesn't match, it's hidden */ - if (ocg_intents_include(desc, fz_to_name(obj)) == 0) + if (ocg_intents_include(desc, pdf_to_name(obj)) == 0) return 1; } - else if (fz_is_array(obj)) + else if (pdf_is_array(obj)) { int match = 0; - len = fz_array_len(obj); + len = pdf_array_len(obj); for (i=0; i<len; i++) { - match |= ocg_intents_include(desc, fz_to_name(fz_array_get(obj, i))); + match |= ocg_intents_include(desc, pdf_to_name(pdf_array_get(obj, i))); if (match) break; } @@ -224,15 +224,15 @@ pdf_is_hidden_ocg(fz_obj *ocg, pdf_csi *csi, fz_obj *rdb) * correspond to entries in the AS list in the OCG config. * Given that we don't handle Zoom or User, or Language * dicts, this is not really a problem. */ - obj = fz_dict_gets(ocg, "Usage"); - if (!fz_is_dict(obj)) + obj = pdf_dict_gets(ocg, "Usage"); + if (!pdf_is_dict(obj)) return 0; /* FIXME: Should look at Zoom (and return hidden if out of * max/min range) */ /* FIXME: Could provide hooks to the caller to check if * User is appropriate - if not return hidden. */ - obj2 = fz_dict_gets(obj, csi->event); - if (strcmp(fz_to_name(fz_dict_gets(obj2, event_state)), "OFF") == 0) + obj2 = pdf_dict_gets(obj, csi->event); + if (strcmp(pdf_to_name(pdf_dict_gets(obj2, event_state)), "OFF") == 0) { return 1; } @@ -244,12 +244,12 @@ pdf_is_hidden_ocg(fz_obj *ocg, pdf_csi *csi, fz_obj *rdb) char *name; int combine, on; - obj = fz_dict_gets(ocg, "VE"); - if (fz_is_array(obj)) { + obj = pdf_dict_gets(ocg, "VE"); + if (pdf_is_array(obj)) { /* FIXME: Calculate visibility from array */ return 0; } - name = fz_to_name(fz_dict_gets(ocg, "P")); + name = pdf_to_name(pdf_dict_gets(ocg, "P")); /* Set combine; Bit 0 set => AND, Bit 1 set => true means * Off, otherwise true means On */ if (strcmp(name, "AllOn") == 0) @@ -269,15 +269,15 @@ pdf_is_hidden_ocg(fz_obj *ocg, pdf_csi *csi, fz_obj *rdb) combine = 0; } - obj = fz_dict_gets(ocg, "OCGs"); + obj = pdf_dict_gets(ocg, "OCGs"); on = combine & 1; - if (fz_is_array(obj)) { + if (pdf_is_array(obj)) { int i, len; - len = fz_array_len(obj); + len = pdf_array_len(obj); for (i = 0; i < len; i++) { int hidden; - hidden = pdf_is_hidden_ocg(fz_array_get(obj, i), csi, rdb); + hidden = pdf_is_hidden_ocg(pdf_array_get(obj, i), csi, rdb); if ((combine & 1) == 0) hidden = !hidden; if (combine & 2) @@ -362,7 +362,7 @@ pdf_show_shade(pdf_csi *csi, fz_shade *shd) } static void -pdf_show_image(pdf_csi *csi, fz_pixmap *image) +pdf_show_image(pdf_csi *csi, fz_image *image) { pdf_gstate *gstate = csi->gstate + csi->gtop; fz_matrix image_ctm; @@ -709,7 +709,7 @@ pdf_show_char(pdf_csi *csi, int cid) if (fontdesc->wmode == 1) { - v = pdf_get_vmtx(ctx, fontdesc, cid); + v = pdf_lookup_vmtx(ctx, fontdesc, cid); tsm.e -= v.x * gstate->size * 0.001f; tsm.f -= v.y * gstate->size * 0.001f; } @@ -767,7 +767,7 @@ pdf_show_char(pdf_csi *csi, int cid) if (fontdesc->wmode == 0) { - h = pdf_get_hmtx(ctx, fontdesc, cid); + h = pdf_lookup_hmtx(ctx, fontdesc, cid); w0 = h.w * 0.001f; tx = (w0 * gstate->size + gstate->char_space) * gstate->scale; csi->tm = fz_concat(fz_translate(tx, 0), csi->tm); @@ -819,6 +819,7 @@ pdf_show_string(pdf_csi *csi, unsigned char *buf, int len) { int w = pdf_decode_cmap(fontdesc->encoding, buf, &cpt); buf += w; + cid = pdf_lookup_cmap(fontdesc->encoding, cpt); if (cid >= 0) pdf_show_char(csi, cid); @@ -830,26 +831,26 @@ pdf_show_string(pdf_csi *csi, unsigned char *buf, int len) } static void -pdf_show_text(pdf_csi *csi, fz_obj *text) +pdf_show_text(pdf_csi *csi, pdf_obj *text) { pdf_gstate *gstate = csi->gstate + csi->gtop; int i; - if (fz_is_array(text)) + if (pdf_is_array(text)) { - int n = fz_array_len(text); + int n = pdf_array_len(text); for (i = 0; i < n; i++) { - fz_obj *item = fz_array_get(text, i); - if (fz_is_string(item)) - pdf_show_string(csi, (unsigned char *)fz_to_str_buf(item), fz_to_str_len(item)); + pdf_obj *item = pdf_array_get(text, i); + if (pdf_is_string(item)) + pdf_show_string(csi, (unsigned char *)pdf_to_str_buf(item), pdf_to_str_len(item)); else - pdf_show_space(csi, - fz_to_real(item) * gstate->size * 0.001f); + pdf_show_space(csi, - pdf_to_real(item) * gstate->size * 0.001f); } } - else if (fz_is_string(text)) + else if (pdf_is_string(text)) { - pdf_show_string(csi, (unsigned char *)fz_to_str_buf(text), fz_to_str_len(text)); + pdf_show_string(csi, (unsigned char *)pdf_to_str_buf(text), pdf_to_str_len(text)); } } @@ -1003,7 +1004,7 @@ pdf_clear_stack(pdf_csi *csi) int i; if (csi->obj) - fz_drop_obj(csi->obj); + pdf_drop_obj(csi->obj); csi->obj = NULL; csi->name[0] = 0; @@ -1334,7 +1335,7 @@ pdf_show_pattern(pdf_csi *csi, pdf_pattern *pat, fz_rect area, int what) } static void -pdf_run_xobject(pdf_csi *csi, fz_obj *resources, pdf_xobject *xobj, fz_matrix transform) +pdf_run_xobject(pdf_csi *csi, pdf_obj *resources, pdf_xobject *xobj, fz_matrix transform) { fz_context *ctx = csi->dev->ctx; pdf_gstate *gstate = NULL; @@ -1343,7 +1344,7 @@ pdf_run_xobject(pdf_csi *csi, fz_obj *resources, pdf_xobject *xobj, fz_matrix tr int popmask; /* Avoid infinite recursion */ - if (xobj == NULL || fz_dict_mark(xobj->me)) + if (xobj == NULL || pdf_dict_mark(xobj->me)) return; fz_var(gstate); @@ -1424,7 +1425,7 @@ pdf_run_xobject(pdf_csi *csi, fz_obj *resources, pdf_xobject *xobj, fz_matrix tr pdf_grestore(csi); } - fz_dict_unmark(xobj->me); + pdf_dict_unmark(xobj->me); } fz_catch(ctx) { @@ -1441,7 +1442,7 @@ pdf_run_xobject(pdf_csi *csi, fz_obj *resources, pdf_xobject *xobj, fz_matrix tr } static void -pdf_run_extgstate(pdf_csi *csi, fz_obj *rdb, fz_obj *extgstate) +pdf_run_extgstate(pdf_csi *csi, pdf_obj *rdb, pdf_obj *extgstate) { fz_context *ctx = csi->dev->ctx; pdf_gstate *gstate = csi->gstate + csi->gtop; @@ -1450,18 +1451,18 @@ pdf_run_extgstate(pdf_csi *csi, fz_obj *rdb, fz_obj *extgstate) pdf_flush_text(csi); - n = fz_dict_len(extgstate); + n = pdf_dict_len(extgstate); for (i = 0; i < n; i++) { - fz_obj *key = fz_dict_get_key(extgstate, i); - fz_obj *val = fz_dict_get_val(extgstate, i); - char *s = fz_to_name(key); + pdf_obj *key = pdf_dict_get_key(extgstate, i); + pdf_obj *val = pdf_dict_get_val(extgstate, i); + char *s = pdf_to_name(key); if (!strcmp(s, "Font")) { - if (fz_is_array(val) && fz_array_len(val) == 2) + if (pdf_is_array(val) && pdf_array_len(val) == 2) { - fz_obj *font = fz_array_get(val, 0); + pdf_obj *font = pdf_array_get(val, 0); if (gstate->font) { @@ -1470,10 +1471,10 @@ pdf_run_extgstate(pdf_csi *csi, fz_obj *rdb, fz_obj *extgstate) } gstate->font = pdf_load_font(csi->xref, rdb, font); - /* RJW: "cannot load font (%d %d R)", fz_to_num(font), fz_to_gen(font) */ + /* RJW: "cannot load font (%d %d R)", pdf_to_num(font), pdf_to_gen(font) */ if (!gstate->font) fz_throw(ctx, "cannot find font in store"); - gstate->size = fz_to_real(fz_array_get(val, 1)); + gstate->size = pdf_to_real(pdf_array_get(val, 1)); } else fz_throw(ctx, "malformed /Font dictionary"); @@ -1482,59 +1483,59 @@ pdf_run_extgstate(pdf_csi *csi, fz_obj *rdb, fz_obj *extgstate) else if (!strcmp(s, "LC")) { csi->dev->flags &= ~(FZ_DEVFLAG_STARTCAP_UNDEFINED | FZ_DEVFLAG_DASHCAP_UNDEFINED | FZ_DEVFLAG_ENDCAP_UNDEFINED); - gstate->stroke_state.start_cap = fz_to_int(val); - gstate->stroke_state.dash_cap = fz_to_int(val); - gstate->stroke_state.end_cap = fz_to_int(val); + gstate->stroke_state.start_cap = pdf_to_int(val); + gstate->stroke_state.dash_cap = pdf_to_int(val); + gstate->stroke_state.end_cap = pdf_to_int(val); } else if (!strcmp(s, "LW")) { csi->dev->flags &= ~FZ_DEVFLAG_LINEWIDTH_UNDEFINED; - gstate->stroke_state.linewidth = fz_to_real(val); + gstate->stroke_state.linewidth = pdf_to_real(val); } else if (!strcmp(s, "LJ")) { csi->dev->flags &= ~FZ_DEVFLAG_LINEJOIN_UNDEFINED; - gstate->stroke_state.linejoin = fz_to_int(val); + gstate->stroke_state.linejoin = pdf_to_int(val); } else if (!strcmp(s, "ML")) { csi->dev->flags &= ~FZ_DEVFLAG_MITERLIMIT_UNDEFINED; - gstate->stroke_state.miterlimit = fz_to_real(val); + gstate->stroke_state.miterlimit = pdf_to_real(val); } else if (!strcmp(s, "D")) { - if (fz_is_array(val) && fz_array_len(val) == 2) + if (pdf_is_array(val) && pdf_array_len(val) == 2) { - fz_obj *dashes = fz_array_get(val, 0); - gstate->stroke_state.dash_len = MAX(fz_array_len(dashes), 32); + pdf_obj *dashes = pdf_array_get(val, 0); + gstate->stroke_state.dash_len = MAX(pdf_array_len(dashes), 32); for (k = 0; k < gstate->stroke_state.dash_len; k++) - gstate->stroke_state.dash_list[k] = fz_to_real(fz_array_get(dashes, k)); - gstate->stroke_state.dash_phase = fz_to_real(fz_array_get(val, 1)); + gstate->stroke_state.dash_list[k] = pdf_to_real(pdf_array_get(dashes, k)); + gstate->stroke_state.dash_phase = pdf_to_real(pdf_array_get(val, 1)); } else fz_throw(ctx, "malformed /D"); } else if (!strcmp(s, "CA")) - gstate->stroke.alpha = fz_to_real(val); + gstate->stroke.alpha = pdf_to_real(val); else if (!strcmp(s, "ca")) - gstate->fill.alpha = fz_to_real(val); + gstate->fill.alpha = pdf_to_real(val); else if (!strcmp(s, "BM")) { - if (fz_is_array(val)) - val = fz_array_get(val, 0); - gstate->blendmode = fz_find_blendmode(fz_to_name(val)); + if (pdf_is_array(val)) + val = pdf_array_get(val, 0); + gstate->blendmode = fz_lookup_blendmode(pdf_to_name(val)); } else if (!strcmp(s, "SMask")) { - if (fz_is_dict(val)) + if (pdf_is_dict(val)) { pdf_xobject *xobj; - fz_obj *group, *luminosity, *bc; + pdf_obj *group, *luminosity, *bc; if (gstate->softmask) { @@ -1542,11 +1543,11 @@ pdf_run_extgstate(pdf_csi *csi, fz_obj *rdb, fz_obj *extgstate) gstate->softmask = NULL; } - group = fz_dict_gets(val, "G"); + group = pdf_dict_gets(val, "G"); if (!group) - fz_throw(ctx, "cannot load softmask xobject (%d %d R)", fz_to_num(val), fz_to_gen(val)); + fz_throw(ctx, "cannot load softmask xobject (%d %d R)", pdf_to_num(val), pdf_to_gen(val)); xobj = pdf_load_xobject(csi->xref, group); - /* RJW: "cannot load xobject (%d %d R)", fz_to_num(val), fz_to_gen(val) */ + /* RJW: "cannot load xobject (%d %d R)", pdf_to_num(val), pdf_to_gen(val) */ colorspace = xobj->colorspace; if (!colorspace) @@ -1557,20 +1558,20 @@ pdf_run_extgstate(pdf_csi *csi, fz_obj *rdb, fz_obj *extgstate) for (k = 0; k < colorspace->n; k++) gstate->softmask_bc[k] = 0; - bc = fz_dict_gets(val, "BC"); - if (fz_is_array(bc)) + bc = pdf_dict_gets(val, "BC"); + if (pdf_is_array(bc)) { for (k = 0; k < colorspace->n; k++) - gstate->softmask_bc[k] = fz_to_real(fz_array_get(bc, k)); + gstate->softmask_bc[k] = pdf_to_real(pdf_array_get(bc, k)); } - luminosity = fz_dict_gets(val, "S"); - if (fz_is_name(luminosity) && !strcmp(fz_to_name(luminosity), "Luminosity")) + luminosity = pdf_dict_gets(val, "S"); + if (pdf_is_name(luminosity) && !strcmp(pdf_to_name(luminosity), "Luminosity")) gstate->luminosity = 1; else gstate->luminosity = 0; } - else if (fz_is_name(val) && !strcmp(fz_to_name(val), "None")) + else if (pdf_is_name(val) && !strcmp(pdf_to_name(val), "None")) { if (gstate->softmask) { @@ -1582,7 +1583,7 @@ pdf_run_extgstate(pdf_csi *csi, fz_obj *rdb, fz_obj *extgstate) else if (!strcmp(s, "TR")) { - if (!fz_is_name(val) || strcmp(fz_to_name(val), "Identity")) + if (!pdf_is_name(val) || strcmp(pdf_to_name(val), "Identity")) fz_warn(ctx, "ignoring transfer function"); } } @@ -1592,9 +1593,9 @@ pdf_run_extgstate(pdf_csi *csi, fz_obj *rdb, fz_obj *extgstate) * Operators */ -static void pdf_run_BDC(pdf_csi *csi, fz_obj *rdb) +static void pdf_run_BDC(pdf_csi *csi, pdf_obj *rdb) { - fz_obj *ocg; + pdf_obj *ocg; /* If we are already in a hidden OCG, then we'll still be hidden - * just increment the depth so we pop back to visibility when we've @@ -1605,14 +1606,14 @@ static void pdf_run_BDC(pdf_csi *csi, fz_obj *rdb) return; } - ocg = fz_dict_gets(fz_dict_gets(rdb, "Properties"), csi->name); + ocg = pdf_dict_gets(pdf_dict_gets(rdb, "Properties"), csi->name); if (!ocg) { /* No Properties array, or name not found in the properties * means visible. */ return; } - if (strcmp(fz_to_name(fz_dict_gets(ocg, "Type")), "OCG") != 0) + if (strcmp(pdf_to_name(pdf_dict_gets(ocg, "Type")), "OCG") != 0) { /* Wrong type of property */ return; @@ -1621,16 +1622,14 @@ static void pdf_run_BDC(pdf_csi *csi, fz_obj *rdb) csi->in_hidden_ocg++; } -static void pdf_run_BI(pdf_csi *csi, fz_obj *rdb, fz_stream *file) +static void pdf_run_BI(pdf_csi *csi, pdf_obj *rdb, fz_stream *file) { fz_context *ctx = csi->dev->ctx; int ch; - char *buf = csi->xref->scratch; - int buflen = sizeof(csi->xref->scratch); - fz_pixmap *img; - fz_obj *obj; + fz_image *img; + pdf_obj *obj; - obj = pdf_parse_dict(csi->xref, file, buf, buflen); + obj = pdf_parse_dict(csi->xref, file, &csi->xref->lexbuf.base); /* RJW: "cannot parse inline image dictionary" */ /* read whitespace after ID keyword */ @@ -1640,12 +1639,12 @@ static void pdf_run_BI(pdf_csi *csi, fz_obj *rdb, fz_stream *file) fz_read_byte(file); img = pdf_load_inline_image(csi->xref, rdb, obj, file); - fz_drop_obj(obj); + pdf_drop_obj(obj); /* RJW: "cannot load inline image" */ pdf_show_image(csi, img); - fz_drop_pixmap(ctx, img); + fz_drop_image(ctx, img); /* find EI */ ch = fz_read_byte(file); @@ -1689,11 +1688,11 @@ static void pdf_run_Bstar(pdf_csi *csi) pdf_show_path(csi, 0, 1, 1, 1); } -static void pdf_run_cs_imp(pdf_csi *csi, fz_obj *rdb, int what) +static void pdf_run_cs_imp(pdf_csi *csi, pdf_obj *rdb, int what) { fz_context *ctx = csi->dev->ctx; fz_colorspace *colorspace; - fz_obj *obj, *dict; + pdf_obj *obj, *dict; if (!strcmp(csi->name, "Pattern")) { @@ -1709,14 +1708,14 @@ static void pdf_run_cs_imp(pdf_csi *csi, fz_obj *rdb, int what) colorspace = fz_device_cmyk; /* No fz_keep_colorspace as static */ else { - dict = fz_dict_gets(rdb, "ColorSpace"); + dict = pdf_dict_gets(rdb, "ColorSpace"); if (!dict) fz_throw(ctx, "cannot find ColorSpace dictionary"); - obj = fz_dict_gets(dict, csi->name); + obj = pdf_dict_gets(dict, csi->name); if (!obj) fz_throw(ctx, "cannot find colorspace resource '%s'", csi->name); colorspace = pdf_load_colorspace(csi->xref, obj); - /* RJW: "cannot load colorspace (%d 0 R)", fz_to_num(obj) */ + /* RJW: "cannot load colorspace (%d 0 R)", pdf_to_num(obj) */ } pdf_set_colorspace(csi, what, colorspace); @@ -1725,7 +1724,7 @@ static void pdf_run_cs_imp(pdf_csi *csi, fz_obj *rdb, int what) } } -static void pdf_run_CS(pdf_csi *csi, fz_obj *rdb) +static void pdf_run_CS(pdf_csi *csi, pdf_obj *rdb) { csi->dev->flags &= ~FZ_DEVFLAG_STROKECOLOR_UNDEFINED; @@ -1733,7 +1732,7 @@ static void pdf_run_CS(pdf_csi *csi, fz_obj *rdb) /* RJW: "cannot set colorspace" */ } -static void pdf_run_cs(pdf_csi *csi, fz_obj *rdb) +static void pdf_run_cs(pdf_csi *csi, pdf_obj *rdb) { csi->dev->flags &= ~FZ_DEVFLAG_FILLCOLOR_UNDEFINED; @@ -1745,41 +1744,41 @@ static void pdf_run_DP(pdf_csi *csi) { } -static void pdf_run_Do(pdf_csi *csi, fz_obj *rdb) +static void pdf_run_Do(pdf_csi *csi, pdf_obj *rdb) { fz_context *ctx = csi->dev->ctx; - fz_obj *dict; - fz_obj *obj; - fz_obj *subtype; + pdf_obj *dict; + pdf_obj *obj; + pdf_obj *subtype; - dict = fz_dict_gets(rdb, "XObject"); + dict = pdf_dict_gets(rdb, "XObject"); if (!dict) fz_throw(ctx, "cannot find XObject dictionary when looking for: '%s'", csi->name); - obj = fz_dict_gets(dict, csi->name); + obj = pdf_dict_gets(dict, csi->name); if (!obj) fz_throw(ctx, "cannot find xobject resource: '%s'", csi->name); - subtype = fz_dict_gets(obj, "Subtype"); - if (!fz_is_name(subtype)) + subtype = pdf_dict_gets(obj, "Subtype"); + if (!pdf_is_name(subtype)) fz_throw(ctx, "no XObject subtype specified"); - if (pdf_is_hidden_ocg(fz_dict_gets(obj, "OC"), csi, rdb)) + if (pdf_is_hidden_ocg(pdf_dict_gets(obj, "OC"), csi, rdb)) return; - if (!strcmp(fz_to_name(subtype), "Form") && fz_dict_gets(obj, "Subtype2")) - subtype = fz_dict_gets(obj, "Subtype2"); + if (!strcmp(pdf_to_name(subtype), "Form") && pdf_dict_gets(obj, "Subtype2")) + subtype = pdf_dict_gets(obj, "Subtype2"); - if (!strcmp(fz_to_name(subtype), "Form")) + if (!strcmp(pdf_to_name(subtype), "Form")) { pdf_xobject *xobj; xobj = pdf_load_xobject(csi->xref, obj); - /* RJW: "cannot load xobject (%d %d R)", fz_to_num(obj), fz_to_gen(obj) */ + /* RJW: "cannot load xobject (%d %d R)", pdf_to_num(obj), pdf_to_gen(obj) */ /* Inherit parent resources, in case this one was empty XXX check where it's loaded */ if (!xobj->resources) - xobj->resources = fz_keep_obj(rdb); + xobj->resources = pdf_keep_obj(rdb); fz_try(ctx) { @@ -1788,40 +1787,41 @@ static void pdf_run_Do(pdf_csi *csi, fz_obj *rdb) fz_catch(ctx) { pdf_drop_xobject(ctx, xobj); - fz_throw(ctx, "cannot draw xobject (%d %d R)", fz_to_num(obj), fz_to_gen(obj)); + fz_throw(ctx, "cannot draw xobject (%d %d R)", pdf_to_num(obj), pdf_to_gen(obj)); } pdf_drop_xobject(ctx, xobj); } - else if (!strcmp(fz_to_name(subtype), "Image")) + else if (!strcmp(pdf_to_name(subtype), "Image")) { if ((csi->dev->hints & FZ_IGNORE_IMAGE) == 0) { - fz_pixmap *img; - img = pdf_load_image(csi->xref, obj); - /* RJW: "cannot load image (%d %d R)", fz_to_num(obj), fz_to_gen(obj) */ + fz_image *img = pdf_load_image(csi->xref, obj); + /* RJW: "cannot load image (%d %d R)", pdf_to_num(obj), pdf_to_gen(obj) */ fz_try(ctx) { pdf_show_image(csi, img); } + fz_always(ctx) + { + fz_drop_image(ctx, img); + } fz_catch(ctx) { - fz_drop_pixmap(ctx, img); fz_rethrow(ctx); } - fz_drop_pixmap(ctx, img); } } - else if (!strcmp(fz_to_name(subtype), "PS")) + else if (!strcmp(pdf_to_name(subtype), "PS")) { fz_warn(ctx, "ignoring XObject with subtype PS"); } else { - fz_throw(ctx, "unknown XObject subtype: '%s'", fz_to_name(subtype)); + fz_throw(ctx, "unknown XObject subtype: '%s'", pdf_to_name(subtype)); } } @@ -1899,12 +1899,12 @@ static void pdf_run_S(pdf_csi *csi) pdf_show_path(csi, 0, 0, 1, 0); } -static void pdf_run_SC_imp(pdf_csi *csi, fz_obj *rdb, int what, pdf_material *mat) +static void pdf_run_SC_imp(pdf_csi *csi, pdf_obj *rdb, int what, pdf_material *mat) { fz_context *ctx = csi->dev->ctx; - fz_obj *patterntype; - fz_obj *dict; - fz_obj *obj; + pdf_obj *patterntype; + pdf_obj *dict; + pdf_obj *obj; int kind; kind = mat->kind; @@ -1921,35 +1921,35 @@ static void pdf_run_SC_imp(pdf_csi *csi, fz_obj *rdb, int what, pdf_material *ma break; case PDF_MAT_PATTERN: - dict = fz_dict_gets(rdb, "Pattern"); + dict = pdf_dict_gets(rdb, "Pattern"); if (!dict) fz_throw(ctx, "cannot find Pattern dictionary"); - obj = fz_dict_gets(dict, csi->name); + obj = pdf_dict_gets(dict, csi->name); if (!obj) fz_throw(ctx, "cannot find pattern resource '%s'", csi->name); - patterntype = fz_dict_gets(obj, "PatternType"); + patterntype = pdf_dict_gets(obj, "PatternType"); - if (fz_to_int(patterntype) == 1) + if (pdf_to_int(patterntype) == 1) { pdf_pattern *pat; pat = pdf_load_pattern(csi->xref, obj); - /* RJW: "cannot load pattern (%d 0 R)", fz_to_num(obj) */ + /* RJW: "cannot load pattern (%d 0 R)", pdf_to_num(obj) */ pdf_set_pattern(csi, what, pat, csi->top > 0 ? csi->stack : NULL); pdf_drop_pattern(ctx, pat); } - else if (fz_to_int(patterntype) == 2) + else if (pdf_to_int(patterntype) == 2) { fz_shade *shd; shd = pdf_load_shading(csi->xref, obj); - /* RJW: "cannot load shading (%d 0 R)", fz_to_num(obj) */ + /* RJW: "cannot load shading (%d 0 R)", pdf_to_num(obj) */ pdf_set_shade(csi, what, shd); fz_drop_shade(ctx, shd); } else { - fz_throw(ctx, "unknown pattern type: %d", fz_to_int(patterntype)); + fz_throw(ctx, "unknown pattern type: %d", pdf_to_int(patterntype)); } break; @@ -1958,7 +1958,7 @@ static void pdf_run_SC_imp(pdf_csi *csi, fz_obj *rdb, int what, pdf_material *ma } } -static void pdf_run_SC(pdf_csi *csi, fz_obj *rdb) +static void pdf_run_SC(pdf_csi *csi, pdf_obj *rdb) { pdf_gstate *gstate = csi->gstate + csi->gtop; csi->dev->flags &= ~FZ_DEVFLAG_STROKECOLOR_UNDEFINED; @@ -1966,7 +1966,7 @@ static void pdf_run_SC(pdf_csi *csi, fz_obj *rdb) /* RJW: "cannot set color and colorspace" */ } -static void pdf_run_sc(pdf_csi *csi, fz_obj *rdb) +static void pdf_run_sc(pdf_csi *csi, pdf_obj *rdb) { pdf_gstate *gstate = csi->gstate + csi->gtop; csi->dev->flags &= ~FZ_DEVFLAG_FILLCOLOR_UNDEFINED; @@ -2000,28 +2000,28 @@ static void pdf_run_TL(pdf_csi *csi) gstate->leading = csi->stack[0]; } -static void pdf_run_Tf(pdf_csi *csi, fz_obj *rdb) +static void pdf_run_Tf(pdf_csi *csi, pdf_obj *rdb) { fz_context *ctx = csi->dev->ctx; pdf_gstate *gstate = csi->gstate + csi->gtop; - fz_obj *dict; - fz_obj *obj; + pdf_obj *dict; + pdf_obj *obj; gstate->size = csi->stack[0]; if (gstate->font) pdf_drop_font(ctx, gstate->font); gstate->font = NULL; - dict = fz_dict_gets(rdb, "Font"); + dict = pdf_dict_gets(rdb, "Font"); if (!dict) fz_throw(ctx, "cannot find Font dictionary"); - obj = fz_dict_gets(dict, csi->name); + obj = pdf_dict_gets(dict, csi->name); if (!obj) fz_throw(ctx, "cannot find font resource: '%s'", csi->name); gstate->font = pdf_load_font(csi->xref, rdb, obj); - /* RJW: "cannot load font (%d 0 R)", fz_to_num(obj) */ + /* RJW: "cannot load font (%d 0 R)", pdf_to_num(obj) */ } static void pdf_run_Tr(pdf_csi *csi) @@ -2141,13 +2141,13 @@ static void pdf_run_cm(pdf_csi *csi) static void pdf_run_d(pdf_csi *csi) { pdf_gstate *gstate = csi->gstate + csi->gtop; - fz_obj *array; + pdf_obj *array; int i; array = csi->obj; - gstate->stroke_state.dash_len = MIN(fz_array_len(array), nelem(gstate->stroke_state.dash_list)); + gstate->stroke_state.dash_len = MIN(pdf_array_len(array), nelem(gstate->stroke_state.dash_list)); for (i = 0; i < gstate->stroke_state.dash_len; i++) - gstate->stroke_state.dash_list[i] = fz_to_real(fz_array_get(array, i)); + gstate->stroke_state.dash_list[i] = pdf_to_real(pdf_array_get(array, i)); gstate->stroke_state.dash_phase = csi->stack[0]; } @@ -2186,22 +2186,22 @@ static void pdf_run_g(pdf_csi *csi) pdf_set_color(csi, PDF_FILL, csi->stack); } -static void pdf_run_gs(pdf_csi *csi, fz_obj *rdb) +static void pdf_run_gs(pdf_csi *csi, pdf_obj *rdb) { - fz_obj *dict; - fz_obj *obj; + pdf_obj *dict; + pdf_obj *obj; fz_context *ctx = csi->dev->ctx; - dict = fz_dict_gets(rdb, "ExtGState"); + dict = pdf_dict_gets(rdb, "ExtGState"); if (!dict) fz_throw(ctx, "cannot find ExtGState dictionary"); - obj = fz_dict_gets(dict, csi->name); + obj = pdf_dict_gets(dict, csi->name); if (!obj) fz_throw(ctx, "cannot find extgstate resource '%s'", csi->name); pdf_run_extgstate(csi, rdb, obj); - /* RJW: "cannot set ExtGState (%d 0 R)", fz_to_num(obj) */ + /* RJW: "cannot set ExtGState (%d 0 R)", pdf_to_num(obj) */ } static void pdf_run_h(pdf_csi *csi) @@ -2286,25 +2286,25 @@ static void pdf_run(pdf_csi *csi) pdf_show_path(csi, 1, 0, 1, 0); } -static void pdf_run_sh(pdf_csi *csi, fz_obj *rdb) +static void pdf_run_sh(pdf_csi *csi, pdf_obj *rdb) { fz_context *ctx = csi->dev->ctx; - fz_obj *dict; - fz_obj *obj; + pdf_obj *dict; + pdf_obj *obj; fz_shade *shd; - dict = fz_dict_gets(rdb, "Shading"); + dict = pdf_dict_gets(rdb, "Shading"); if (!dict) fz_throw(ctx, "cannot find shading dictionary"); - obj = fz_dict_gets(dict, csi->name); + obj = pdf_dict_gets(dict, csi->name); if (!obj) fz_throw(ctx, "cannot find shading resource: '%s'", csi->name); if ((csi->dev->hints & FZ_IGNORE_SHADE) == 0) { shd = pdf_load_shading(csi->xref, obj); - /* RJW: "cannot load shading (%d %d R)", fz_to_num(obj), fz_to_gen(obj) */ + /* RJW: "cannot load shading (%d %d R)", pdf_to_num(obj), pdf_to_gen(obj) */ fz_try(ctx) { pdf_show_shade(csi, shd); @@ -2384,7 +2384,7 @@ static void pdf_run_dquote(pdf_csi *csi) #define C(a,b,c) (a | b << 8 | c << 16) static void -pdf_run_keyword(pdf_csi *csi, fz_obj *rdb, fz_stream *file, char *buf) +pdf_run_keyword(pdf_csi *csi, pdf_obj *rdb, fz_stream *file, char *buf) { fz_context *ctx = csi->dev->ctx; int key; @@ -2522,10 +2522,10 @@ pdf_run_keyword(pdf_csi *csi, fz_obj *rdb, fz_stream *file, char *buf) } static void -pdf_run_stream(pdf_csi *csi, fz_obj *rdb, fz_stream *file, char *buf, int buflen) +pdf_run_stream(pdf_csi *csi, pdf_obj *rdb, fz_stream *file, pdf_lexbuf *buf) { fz_context *ctx = csi->dev->ctx; - int tok, len, in_array; + int tok, in_array; /* make sure we have a clean slate if we come here from flush_text */ pdf_clear_stack(csi); @@ -2550,7 +2550,7 @@ pdf_run_stream(pdf_csi *csi, fz_obj *rdb, fz_stream *file, char *buf, int buflen csi->cookie->progress++; } - tok = pdf_lex(file, buf, buflen, &len); + tok = pdf_lex(file, buf); /* RJW: "lexical error in content stream" */ if (in_array) @@ -2559,19 +2559,24 @@ pdf_run_stream(pdf_csi *csi, fz_obj *rdb, fz_stream *file, char *buf, int buflen { in_array = 0; } - else if (tok == PDF_TOK_INT || tok == PDF_TOK_REAL) + else if (tok == PDF_TOK_REAL) + { + pdf_gstate *gstate = csi->gstate + csi->gtop; + pdf_show_space(csi, -buf->f * gstate->size * 0.001f); + } + else if (tok == PDF_TOK_INT) { pdf_gstate *gstate = csi->gstate + csi->gtop; - pdf_show_space(csi, -fz_atof(buf) * gstate->size * 0.001f); + pdf_show_space(csi, -buf->i * gstate->size * 0.001f); } else if (tok == PDF_TOK_STRING) { - pdf_show_string(csi, (unsigned char *)buf, len); + pdf_show_string(csi, (unsigned char *)buf->scratch, buf->len); } else if (tok == PDF_TOK_KEYWORD) { - if (!strcmp(buf, "Tw") || !strcmp(buf, "Tc")) - fz_warn(ctx, "ignoring keyword '%s' inside array", buf); + if (!strcmp(buf->scratch, "Tw") || !strcmp(buf->scratch, "Tc")) + fz_warn(ctx, "ignoring keyword '%s' inside array", buf->scratch); else fz_throw(ctx, "syntax error in array"); } @@ -2590,7 +2595,7 @@ pdf_run_stream(pdf_csi *csi, fz_obj *rdb, fz_stream *file, char *buf, int buflen case PDF_TOK_OPEN_ARRAY: if (!csi->in_text) { - csi->obj = pdf_parse_array(csi->xref, file, buf, buflen); + csi->obj = pdf_parse_array(csi->xref, file, buf); /* RJW: "cannot parse array" */ } else @@ -2600,38 +2605,38 @@ pdf_run_stream(pdf_csi *csi, fz_obj *rdb, fz_stream *file, char *buf, int buflen break; case PDF_TOK_OPEN_DICT: - csi->obj = pdf_parse_dict(csi->xref, file, buf, buflen); + csi->obj = pdf_parse_dict(csi->xref, file, buf); /* RJW: "cannot parse dictionary" */ break; case PDF_TOK_NAME: - fz_strlcpy(csi->name, buf, sizeof(csi->name)); + fz_strlcpy(csi->name, buf->scratch, sizeof(csi->name)); break; case PDF_TOK_INT: - csi->stack[csi->top] = atoi(buf); + csi->stack[csi->top] = buf->i; csi->top ++; break; case PDF_TOK_REAL: - csi->stack[csi->top] = fz_atof(buf); + csi->stack[csi->top] = buf->f; csi->top ++; break; case PDF_TOK_STRING: - if (len <= sizeof(csi->string)) + if (buf->len <= sizeof(csi->string)) { - memcpy(csi->string, buf, len); - csi->string_len = len; + memcpy(csi->string, buf->scratch, buf->len); + csi->string_len = buf->len; } else { - csi->obj = fz_new_string(ctx, buf, len); + csi->obj = pdf_new_string(ctx, buf->scratch, buf->len); } break; case PDF_TOK_KEYWORD: - pdf_run_keyword(csi, rdb, file, buf); + pdf_run_keyword(csi, rdb, file, buf->scratch); /* RJW: "cannot run keyword" */ pdf_clear_stack(csi); break; @@ -2647,11 +2652,10 @@ pdf_run_stream(pdf_csi *csi, fz_obj *rdb, fz_stream *file, char *buf, int buflen */ static void -pdf_run_buffer(pdf_csi *csi, fz_obj *rdb, fz_buffer *contents) +pdf_run_buffer(pdf_csi *csi, pdf_obj *rdb, fz_buffer *contents) { fz_context *ctx = csi->dev->ctx; - int len = sizeof csi->xref->scratch; - char *buf = NULL; + pdf_lexbuf_large *buf; fz_stream * file = NULL; int save_in_text; @@ -2663,13 +2667,14 @@ pdf_run_buffer(pdf_csi *csi, fz_obj *rdb, fz_buffer *contents) fz_try(ctx) { - buf = fz_malloc(ctx, len); /* we must be re-entrant for type3 fonts */ + buf = fz_malloc(ctx, sizeof(*buf)); /* we must be re-entrant for type3 fonts */ + buf->base.size = PDF_LEXBUF_LARGE; file = fz_open_buffer(ctx, contents); save_in_text = csi->in_text; csi->in_text = 0; fz_try(ctx) { - pdf_run_stream(csi, rdb, file, buf, len); + pdf_run_stream(csi, rdb, file, &buf->base); } fz_catch(ctx) { @@ -2677,14 +2682,15 @@ pdf_run_buffer(pdf_csi *csi, fz_obj *rdb, fz_buffer *contents) } csi->in_text = save_in_text; } - fz_catch(ctx) + fz_always(ctx) { fz_close(file); fz_free(ctx, buf); + } + fz_catch(ctx) + { fz_throw(ctx, "cannot parse context stream"); } - fz_close(file); - fz_free(ctx, buf); } void @@ -2730,7 +2736,7 @@ pdf_run_page_with_usage(pdf_document *xref, pdf_page *page, fz_device *dev, fz_m cookie->progress++; } - flags = fz_to_int(fz_dict_gets(annot->obj, "F")); + flags = pdf_to_int(pdf_dict_gets(annot->obj, "F")); /* TODO: NoZoom and NoRotate */ if (flags & (1 << 0)) /* Invisible */ @@ -2743,7 +2749,7 @@ pdf_run_page_with_usage(pdf_document *xref, pdf_page *page, fz_device *dev, fz_m continue; csi = pdf_new_csi(xref, dev, ctm, event, cookie, NULL); - if (!pdf_is_hidden_ocg(fz_dict_gets(annot->obj, "OC"), csi, page->resources)) + if (!pdf_is_hidden_ocg(pdf_dict_gets(annot->obj, "OC"), csi, page->resources)) { fz_try(ctx) { @@ -2769,7 +2775,7 @@ pdf_run_page(pdf_document *xref, pdf_page *page, fz_device *dev, fz_matrix ctm, } void -pdf_run_glyph(pdf_document *xref, fz_obj *resources, fz_buffer *contents, fz_device *dev, fz_matrix ctm, void *gstate) +pdf_run_glyph(pdf_document *xref, pdf_obj *resources, fz_buffer *contents, fz_device *dev, fz_matrix ctm, void *gstate) { pdf_csi *csi = pdf_new_csi(xref, dev, ctm, "View", NULL, gstate); fz_context *ctx = xref->ctx; diff --git a/pdf/pdf_lex.c b/pdf/pdf_lex.c index 24828412..6774167a 100644 --- a/pdf/pdf_lex.c +++ b/pdf/pdf_lex.c @@ -1,5 +1,5 @@ -#include "fitz.h" -#include "mupdf.h" +#include "fitz-internal.h" +#include "mupdf-internal.h" #define IS_NUMBER \ '+':case'-':case'.':case'0':case'1':case'2':case'3':\ @@ -63,87 +63,106 @@ lex_comment(fz_stream *f) } static int -lex_number(fz_stream *f, char *s, int n, int *tok) +lex_number(fz_stream *f, pdf_lexbuf *buf, int c) { - char *buf = s; - *tok = PDF_TOK_INT; + int neg = 0; + int i = 0; + int n; + int d; + float v; /* Initially we might have +, -, . or a digit */ - if (n > 1) + switch (c) + { + case '.': + goto loop_after_dot; + case '-': + neg = 1; + break; + case '+': + break; + default: /* Must be a digit */ + i = c - '0'; + break; + } + + while (1) { int c = fz_read_byte(f); switch (c) { case '.': - *tok = PDF_TOK_REAL; - *s++ = c; - n--; goto loop_after_dot; - case '+': - case '-': case RANGE_0_9: - *s++ = c; - n--; - goto loop_after_sign; + i = 10*i + c - '0'; + /* FIXME: Need overflow check here; do we care? */ + break; default: fz_unread_byte(f); - goto end; + /* Fallthrough */ case EOF: - goto end; + if (neg) + i = -i; + buf->i = i; + return PDF_TOK_INT; } } - /* We can't accept a sign from here on in, just . or a digit */ -loop_after_sign: - while (n > 1) + /* In here, we've seen a dot, so can accept just digits */ +loop_after_dot: + n = 0; + d = 1; + while (1) { int c = fz_read_byte(f); switch (c) { - case '.': - *tok = PDF_TOK_REAL; - *s++ = c; - n--; - goto loop_after_dot; case RANGE_0_9: - *s++ = c; + if (d >= INT_MAX/10) + goto underflow; + n = n*10 + (c - '0'); + d *= 10; break; default: fz_unread_byte(f); - goto end; + /* Fallthrough */ case EOF: - goto end; + v = (float)i + ((float)n / (float)d); + if (neg) + v = -v; + buf->f = v; + return PDF_TOK_REAL; } - n--; } - /* In here, we've seen a dot, so can accept just digits */ -loop_after_dot: - while (n > 1) +underflow: + /* Ignore any digits after here, because they are too small */ + while (1) { int c = fz_read_byte(f); switch (c) { case RANGE_0_9: - *s++ = c; break; default: fz_unread_byte(f); - goto end; + /* Fallthrough */ case EOF: - goto end; + v = (float)i + ((float)n / (float)d); + if (neg) + v = -v; + buf->f = v; + return PDF_TOK_REAL; } - n--; } - -end: - *s = '\0'; - return s-buf; } static void -lex_name(fz_stream *f, char *s, int n) +lex_name(fz_stream *f, pdf_lexbuf *buf) { + char *s = buf->scratch; + int n = buf->size; + while (n > 1) { int c = fz_read_byte(f); @@ -208,6 +227,7 @@ lex_name(fz_stream *f, char *s, int n) } end: *s = '\0'; + buf->len = s - buf->scratch; } static int @@ -380,7 +400,7 @@ pdf_token_from_keyword(char *key) } int -pdf_lex(fz_stream *f, char *buf, int n, int *sl) +pdf_lex(fz_stream *f, pdf_lexbuf *buf) { while (1) { @@ -396,11 +416,10 @@ pdf_lex(fz_stream *f, char *buf, int n, int *sl) lex_comment(f); break; case '/': - lex_name(f, buf, n); - *sl = strlen(buf); + lex_name(f, buf); return PDF_TOK_NAME; case '(': - *sl = lex_string(f, buf, n); + buf->len = lex_string(f, buf->scratch, buf->size); return PDF_TOK_STRING; case ')': fz_warn(f->ctx, "lexical error (unexpected ')')"); @@ -414,7 +433,7 @@ pdf_lex(fz_stream *f, char *buf, int n, int *sl) else { fz_unread_byte(f); - *sl = lex_hex_string(f, buf, n); + buf->len = lex_hex_string(f, buf->scratch, buf->size); return PDF_TOK_STRING; } case '>': @@ -434,17 +453,11 @@ pdf_lex(fz_stream *f, char *buf, int n, int *sl) case '}': return PDF_TOK_CLOSE_BRACE; case IS_NUMBER: - { - int tok; - fz_unread_byte(f); - *sl = lex_number(f, buf, n, &tok); - return tok; - } + return lex_number(f, buf, c); default: /* isregular: !isdelim && !iswhite && c != EOF */ fz_unread_byte(f); - lex_name(f, buf, n); - *sl = strlen(buf); - return pdf_token_from_keyword(buf); + lex_name(f, buf); + return pdf_token_from_keyword(buf->scratch); } } } diff --git a/pdf/pdf_metrics.c b/pdf/pdf_metrics.c index fc888257..888757c0 100644 --- a/pdf/pdf_metrics.c +++ b/pdf/pdf_metrics.c @@ -1,5 +1,5 @@ -#include "fitz.h" -#include "mupdf.h" +#include "fitz-internal.h" +#include "mupdf-internal.h" void pdf_set_font_wmode(fz_context *ctx, pdf_font_desc *font, int wmode) @@ -85,7 +85,7 @@ pdf_end_vmtx(fz_context *ctx, pdf_font_desc *font) } pdf_hmtx -pdf_get_hmtx(fz_context *ctx, pdf_font_desc *font, int cid) +pdf_lookup_hmtx(fz_context *ctx, pdf_font_desc *font, int cid) { int l = 0; int r = font->hmtx_len - 1; @@ -110,7 +110,7 @@ notfound: } pdf_vmtx -pdf_get_vmtx(fz_context *ctx, pdf_font_desc *font, int cid) +pdf_lookup_vmtx(fz_context *ctx, pdf_font_desc *font, int cid) { pdf_hmtx h; pdf_vmtx v; @@ -133,7 +133,7 @@ pdf_get_vmtx(fz_context *ctx, pdf_font_desc *font, int cid) } notfound: - h = pdf_get_hmtx(ctx, font, cid); + h = pdf_lookup_hmtx(ctx, font, cid); v = font->dvmtx; v.x = h.w / 2; return v; diff --git a/pdf/pdf_nametree.c b/pdf/pdf_nametree.c index c78e238d..b24d2c24 100644 --- a/pdf/pdf_nametree.c +++ b/pdf/pdf_nametree.c @@ -1,55 +1,55 @@ -#include "fitz.h" -#include "mupdf.h" +#include "fitz-internal.h" +#include "mupdf-internal.h" -static fz_obj * -pdf_lookup_name_imp(fz_context *ctx, fz_obj *node, fz_obj *needle) +static pdf_obj * +pdf_lookup_name_imp(fz_context *ctx, pdf_obj *node, pdf_obj *needle) { - fz_obj *kids = fz_dict_gets(node, "Kids"); - fz_obj *names = fz_dict_gets(node, "Names"); + pdf_obj *kids = pdf_dict_gets(node, "Kids"); + pdf_obj *names = pdf_dict_gets(node, "Names"); - if (fz_is_array(kids)) + if (pdf_is_array(kids)) { int l = 0; - int r = fz_array_len(kids) - 1; + int r = pdf_array_len(kids) - 1; while (l <= r) { int m = (l + r) >> 1; - fz_obj *kid = fz_array_get(kids, m); - fz_obj *limits = fz_dict_gets(kid, "Limits"); - fz_obj *first = fz_array_get(limits, 0); - fz_obj *last = fz_array_get(limits, 1); + pdf_obj *kid = pdf_array_get(kids, m); + pdf_obj *limits = pdf_dict_gets(kid, "Limits"); + pdf_obj *first = pdf_array_get(limits, 0); + pdf_obj *last = pdf_array_get(limits, 1); - if (fz_objcmp(needle, first) < 0) + if (pdf_objcmp(needle, first) < 0) r = m - 1; - else if (fz_objcmp(needle, last) > 0) + else if (pdf_objcmp(needle, last) > 0) l = m + 1; else { - fz_obj *obj; + pdf_obj *obj; - if (fz_dict_mark(node)) + if (pdf_dict_mark(node)) break; obj = pdf_lookup_name_imp(ctx, kid, needle); - fz_dict_unmark(node); + pdf_dict_unmark(node); return obj; } } } - if (fz_is_array(names)) + if (pdf_is_array(names)) { int l = 0; - int r = (fz_array_len(names) / 2) - 1; + int r = (pdf_array_len(names) / 2) - 1; while (l <= r) { int m = (l + r) >> 1; int c; - fz_obj *key = fz_array_get(names, m * 2); - fz_obj *val = fz_array_get(names, m * 2 + 1); + pdf_obj *key = pdf_array_get(names, m * 2); + pdf_obj *val = pdf_array_get(names, m * 2 + 1); - c = fz_objcmp(needle, key); + c = pdf_objcmp(needle, key); if (c < 0) r = m - 1; else if (c > 0) @@ -61,49 +61,49 @@ pdf_lookup_name_imp(fz_context *ctx, fz_obj *node, fz_obj *needle) /* Spec says names should be sorted (hence the binary search, * above), but Acrobat copes with non-sorted. Drop back to a * simple search if the binary search fails. */ - r = fz_array_len(names)/2; + r = pdf_array_len(names)/2; for (l = 0; l < r; l++) - if (!fz_objcmp(needle, fz_array_get(names, l * 2))) - return fz_array_get(names, l * 2 + 1); + if (!pdf_objcmp(needle, pdf_array_get(names, l * 2))) + return pdf_array_get(names, l * 2 + 1); } return NULL; } -fz_obj * -pdf_lookup_name(pdf_document *xref, char *which, fz_obj *needle) +pdf_obj * +pdf_lookup_name(pdf_document *xref, char *which, pdf_obj *needle) { fz_context *ctx = xref->ctx; - fz_obj *root = fz_dict_gets(xref->trailer, "Root"); - fz_obj *names = fz_dict_gets(root, "Names"); - fz_obj *tree = fz_dict_gets(names, which); + pdf_obj *root = pdf_dict_gets(xref->trailer, "Root"); + pdf_obj *names = pdf_dict_gets(root, "Names"); + pdf_obj *tree = pdf_dict_gets(names, which); return pdf_lookup_name_imp(ctx, tree, needle); } -fz_obj * -pdf_lookup_dest(pdf_document *xref, fz_obj *needle) +pdf_obj * +pdf_lookup_dest(pdf_document *xref, pdf_obj *needle) { fz_context *ctx = xref->ctx; - fz_obj *root = fz_dict_gets(xref->trailer, "Root"); - fz_obj *dests = fz_dict_gets(root, "Dests"); - fz_obj *names = fz_dict_gets(root, "Names"); - fz_obj *dest = NULL; + pdf_obj *root = pdf_dict_gets(xref->trailer, "Root"); + pdf_obj *dests = pdf_dict_gets(root, "Dests"); + pdf_obj *names = pdf_dict_gets(root, "Names"); + pdf_obj *dest = NULL; /* PDF 1.1 has destinations in a dictionary */ if (dests) { - if (fz_is_name(needle)) - return fz_dict_get(dests, needle); + if (pdf_is_name(needle)) + return pdf_dict_get(dests, needle); else - return fz_dict_gets(dests, fz_to_str_buf(needle)); + return pdf_dict_gets(dests, pdf_to_str_buf(needle)); } /* PDF 1.2 has destinations in a name tree */ if (names && !dest) { - fz_obj *tree = fz_dict_gets(names, "Dests"); + pdf_obj *tree = pdf_dict_gets(names, "Dests"); return pdf_lookup_name_imp(ctx, tree, needle); } @@ -111,33 +111,33 @@ pdf_lookup_dest(pdf_document *xref, fz_obj *needle) } static void -pdf_load_name_tree_imp(fz_obj *dict, pdf_document *xref, fz_obj *node) +pdf_load_name_tree_imp(pdf_obj *dict, pdf_document *xref, pdf_obj *node) { fz_context *ctx = xref->ctx; - fz_obj *kids = fz_dict_gets(node, "Kids"); - fz_obj *names = fz_dict_gets(node, "Names"); + pdf_obj *kids = pdf_dict_gets(node, "Kids"); + pdf_obj *names = pdf_dict_gets(node, "Names"); int i; - if (kids && !fz_dict_mark(node)) + if (kids && !pdf_dict_mark(node)) { - for (i = 0; i < fz_array_len(kids); i++) - pdf_load_name_tree_imp(dict, xref, fz_array_get(kids, i)); - fz_dict_unmark(node); + for (i = 0; i < pdf_array_len(kids); i++) + pdf_load_name_tree_imp(dict, xref, pdf_array_get(kids, i)); + pdf_dict_unmark(node); } if (names) { - for (i = 0; i + 1 < fz_array_len(names); i += 2) + for (i = 0; i + 1 < pdf_array_len(names); i += 2) { - fz_obj *key = fz_array_get(names, i); - fz_obj *val = fz_array_get(names, i + 1); - if (fz_is_string(key)) + pdf_obj *key = pdf_array_get(names, i); + pdf_obj *val = pdf_array_get(names, i + 1); + if (pdf_is_string(key)) { key = pdf_to_utf8_name(ctx, key); fz_dict_put(dict, key, val); - fz_drop_obj(key); + pdf_drop_obj(key); } - else if (fz_is_name(key)) + else if (pdf_is_name(key)) { fz_dict_put(dict, key, val); } @@ -145,17 +145,17 @@ pdf_load_name_tree_imp(fz_obj *dict, pdf_document *xref, fz_obj *node) } } -fz_obj * +pdf_obj * pdf_load_name_tree(pdf_document *xref, char *which) { fz_context *ctx = xref->ctx; - fz_obj *root = fz_dict_gets(xref->trailer, "Root"); - fz_obj *names = fz_dict_gets(root, "Names"); - fz_obj *tree = fz_dict_gets(names, which); - if (fz_is_dict(tree)) + pdf_obj *root = pdf_dict_gets(xref->trailer, "Root"); + pdf_obj *names = pdf_dict_gets(root, "Names"); + pdf_obj *tree = pdf_dict_gets(names, which); + if (pdf_is_dict(tree)) { - fz_obj *dict = fz_new_dict(ctx, 100); + pdf_obj *dict = pdf_new_dict(ctx, 100); pdf_load_name_tree_imp(dict, xref, tree); return dict; } diff --git a/pdf/pdf_outline.c b/pdf/pdf_outline.c index e5c87f8c..d4bea75a 100644 --- a/pdf/pdf_outline.c +++ b/pdf/pdf_outline.c @@ -1,13 +1,13 @@ -#include "fitz.h" -#include "mupdf.h" +#include "fitz-internal.h" +#include "mupdf-internal.h" static fz_outline * -pdf_load_outline_imp(pdf_document *xref, fz_obj *dict) +pdf_load_outline_imp(pdf_document *xref, pdf_obj *dict) { fz_context *ctx = xref->ctx; fz_outline *node, **prev, *first; - fz_obj *obj; - fz_obj *odict = dict; + pdf_obj *obj; + pdf_obj *odict = dict; fz_var(dict); @@ -15,9 +15,9 @@ pdf_load_outline_imp(pdf_document *xref, fz_obj *dict) { first = NULL; prev = &first; - while (dict && fz_is_dict(dict)) + while (dict && pdf_is_dict(dict)) { - if (fz_dict_mark(dict)) + if (pdf_dict_mark(dict)) break; node = fz_malloc_struct(ctx, fz_outline); node->title = NULL; @@ -27,31 +27,31 @@ pdf_load_outline_imp(pdf_document *xref, fz_obj *dict) *prev = node; prev = &node->next; - obj = fz_dict_gets(dict, "Title"); + obj = pdf_dict_gets(dict, "Title"); if (obj) node->title = pdf_to_utf8(ctx, obj); - if ((obj = fz_dict_gets(dict, "Dest"))) + if ((obj = pdf_dict_gets(dict, "Dest"))) node->dest = pdf_parse_link_dest(xref, obj); - else if ((obj = fz_dict_gets(dict, "A"))) + else if ((obj = pdf_dict_gets(dict, "A"))) node->dest = pdf_parse_action(xref, obj); - obj = fz_dict_gets(dict, "First"); + obj = pdf_dict_gets(dict, "First"); if (obj) node->down = pdf_load_outline_imp(xref, obj); - dict = fz_dict_gets(dict, "Next"); + dict = pdf_dict_gets(dict, "Next"); } } fz_catch(ctx) { - for (dict = odict; dict && fz_dict_marked(dict); dict = fz_dict_gets(dict, "Next")) - fz_dict_unmark(dict); + for (dict = odict; dict && pdf_dict_marked(dict); dict = pdf_dict_gets(dict, "Next")) + pdf_dict_unmark(dict); fz_rethrow(ctx); } - for (dict = odict; dict && fz_dict_marked(dict); dict = fz_dict_gets(dict, "Next")) - fz_dict_unmark(dict); + for (dict = odict; dict && pdf_dict_marked(dict); dict = pdf_dict_gets(dict, "Next")) + pdf_dict_unmark(dict); return first; } @@ -59,11 +59,11 @@ pdf_load_outline_imp(pdf_document *xref, fz_obj *dict) fz_outline * pdf_load_outline(pdf_document *xref) { - fz_obj *root, *obj, *first; + pdf_obj *root, *obj, *first; - root = fz_dict_gets(xref->trailer, "Root"); - obj = fz_dict_gets(root, "Outlines"); - first = fz_dict_gets(obj, "First"); + root = pdf_dict_gets(xref->trailer, "Root"); + obj = pdf_dict_gets(root, "Outlines"); + first = pdf_dict_gets(obj, "First"); if (first) return pdf_load_outline_imp(xref, first); diff --git a/pdf/pdf_page.c b/pdf/pdf_page.c index f2bf713e..c4083d20 100644 --- a/pdf/pdf_page.c +++ b/pdf/pdf_page.c @@ -1,128 +1,128 @@ -#include "fitz.h" -#include "mupdf.h" +#include "fitz-internal.h" +#include "mupdf-internal.h" struct info { - fz_obj *resources; - fz_obj *mediabox; - fz_obj *cropbox; - fz_obj *rotate; + pdf_obj *resources; + pdf_obj *mediabox; + pdf_obj *cropbox; + pdf_obj *rotate; }; static void -put_marker_bool(fz_context *ctx, fz_obj *rdb, char *marker, int val) +put_marker_bool(fz_context *ctx, pdf_obj *rdb, char *marker, int val) { - fz_obj *tmp; + pdf_obj *tmp; - tmp = fz_new_bool(ctx, val); + tmp = pdf_new_bool(ctx, val); fz_try(ctx) { - fz_dict_puts(rdb, marker, tmp); + pdf_dict_puts(rdb, marker, tmp); } fz_catch(ctx) { - fz_drop_obj(tmp); + pdf_drop_obj(tmp); fz_rethrow(ctx); } - fz_drop_obj(tmp); + pdf_drop_obj(tmp); } static void -pdf_load_page_tree_node(pdf_document *xref, fz_obj *node, struct info info) +pdf_load_page_tree_node(pdf_document *xref, pdf_obj *node, struct info info) { - fz_obj *dict, *kids, *count; - fz_obj *obj; + pdf_obj *dict, *kids, *count; + pdf_obj *obj; int i, n; fz_context *ctx = xref->ctx; /* prevent infinite recursion */ - if (!node || fz_dict_mark(node)) + if (!node || pdf_dict_mark(node)) return; fz_try(ctx) { - kids = fz_dict_gets(node, "Kids"); - count = fz_dict_gets(node, "Count"); + kids = pdf_dict_gets(node, "Kids"); + count = pdf_dict_gets(node, "Count"); - if (fz_is_array(kids) && fz_is_int(count)) + if (pdf_is_array(kids) && pdf_is_int(count)) { - obj = fz_dict_gets(node, "Resources"); + obj = pdf_dict_gets(node, "Resources"); if (obj) info.resources = obj; - obj = fz_dict_gets(node, "MediaBox"); + obj = pdf_dict_gets(node, "MediaBox"); if (obj) info.mediabox = obj; - obj = fz_dict_gets(node, "CropBox"); + obj = pdf_dict_gets(node, "CropBox"); if (obj) info.cropbox = obj; - obj = fz_dict_gets(node, "Rotate"); + obj = pdf_dict_gets(node, "Rotate"); if (obj) info.rotate = obj; - n = fz_array_len(kids); + n = pdf_array_len(kids); for (i = 0; i < n; i++) { - obj = fz_array_get(kids, i); + obj = pdf_array_get(kids, i); pdf_load_page_tree_node(xref, obj, info); } } - else if ((dict = fz_to_dict(node)) != NULL) + else if ((dict = pdf_to_dict(node)) != NULL) { - if (info.resources && !fz_dict_gets(dict, "Resources")) - fz_dict_puts(dict, "Resources", info.resources); - if (info.mediabox && !fz_dict_gets(dict, "MediaBox")) - fz_dict_puts(dict, "MediaBox", info.mediabox); - if (info.cropbox && !fz_dict_gets(dict, "CropBox")) - fz_dict_puts(dict, "CropBox", info.cropbox); - if (info.rotate && !fz_dict_gets(dict, "Rotate")) - fz_dict_puts(dict, "Rotate", info.rotate); + if (info.resources && !pdf_dict_gets(dict, "Resources")) + pdf_dict_puts(dict, "Resources", info.resources); + if (info.mediabox && !pdf_dict_gets(dict, "MediaBox")) + pdf_dict_puts(dict, "MediaBox", info.mediabox); + if (info.cropbox && !pdf_dict_gets(dict, "CropBox")) + pdf_dict_puts(dict, "CropBox", info.cropbox); + if (info.rotate && !pdf_dict_gets(dict, "Rotate")) + pdf_dict_puts(dict, "Rotate", info.rotate); if (xref->page_len == xref->page_cap) { fz_warn(ctx, "found more pages than expected"); xref->page_cap ++; - xref->page_refs = fz_resize_array(ctx, xref->page_refs, xref->page_cap, sizeof(fz_obj*)); - xref->page_objs = fz_resize_array(ctx, xref->page_objs, xref->page_cap, sizeof(fz_obj*)); + xref->page_refs = fz_resize_array(ctx, xref->page_refs, xref->page_cap, sizeof(pdf_obj*)); + xref->page_objs = fz_resize_array(ctx, xref->page_objs, xref->page_cap, sizeof(pdf_obj*)); } - xref->page_refs[xref->page_len] = fz_keep_obj(node); - xref->page_objs[xref->page_len] = fz_keep_obj(dict); + xref->page_refs[xref->page_len] = pdf_keep_obj(node); + xref->page_objs[xref->page_len] = pdf_keep_obj(dict); xref->page_len ++; } } fz_catch(ctx) { - fz_dict_unmark(node); + pdf_dict_unmark(node); fz_rethrow(ctx); } - fz_dict_unmark(node); + pdf_dict_unmark(node); } static void pdf_load_page_tree(pdf_document *xref) { fz_context *ctx = xref->ctx; - fz_obj *catalog; - fz_obj *pages; - fz_obj *count; + pdf_obj *catalog; + pdf_obj *pages; + pdf_obj *count; struct info info; if (xref->page_len) return; - catalog = fz_dict_gets(xref->trailer, "Root"); - pages = fz_dict_gets(catalog, "Pages"); - count = fz_dict_gets(pages, "Count"); + catalog = pdf_dict_gets(xref->trailer, "Root"); + pages = pdf_dict_gets(catalog, "Pages"); + count = pdf_dict_gets(pages, "Count"); - if (!fz_is_dict(pages)) + if (!pdf_is_dict(pages)) fz_throw(ctx, "missing page tree"); - if (!fz_is_int(count)) + if (!pdf_is_int(count)) fz_throw(ctx, "missing page count"); - xref->page_cap = fz_to_int(count); + xref->page_cap = pdf_to_int(count); xref->page_len = 0; - xref->page_refs = fz_malloc_array(ctx, xref->page_cap, sizeof(fz_obj*)); - xref->page_objs = fz_malloc_array(ctx, xref->page_cap, sizeof(fz_obj*)); + xref->page_refs = fz_malloc_array(ctx, xref->page_cap, sizeof(pdf_obj*)); + xref->page_objs = fz_malloc_array(ctx, xref->page_cap, sizeof(pdf_obj*)); info.resources = NULL; info.mediabox = NULL; @@ -140,84 +140,84 @@ pdf_count_pages(pdf_document *xref) } int -pdf_find_page_number(pdf_document *xref, fz_obj *page) +pdf_lookup_page_number(pdf_document *xref, pdf_obj *page) { - int i, num = fz_to_num(page); + int i, num = pdf_to_num(page); pdf_load_page_tree(xref); for (i = 0; i < xref->page_len; i++) - if (num == fz_to_num(xref->page_refs[i])) + if (num == pdf_to_num(xref->page_refs[i])) return i; return -1; } /* We need to know whether to install a page-level transparency group */ -static int pdf_resources_use_blending(fz_context *ctx, fz_obj *rdb); +static int pdf_resources_use_blending(fz_context *ctx, pdf_obj *rdb); static int -pdf_extgstate_uses_blending(fz_context *ctx, fz_obj *dict) +pdf_extgstate_uses_blending(fz_context *ctx, pdf_obj *dict) { - fz_obj *obj = fz_dict_gets(dict, "BM"); - if (fz_is_name(obj) && strcmp(fz_to_name(obj), "Normal")) + pdf_obj *obj = pdf_dict_gets(dict, "BM"); + if (pdf_is_name(obj) && strcmp(pdf_to_name(obj), "Normal")) return 1; return 0; } static int -pdf_pattern_uses_blending(fz_context *ctx, fz_obj *dict) +pdf_pattern_uses_blending(fz_context *ctx, pdf_obj *dict) { - fz_obj *obj; - obj = fz_dict_gets(dict, "Resources"); + pdf_obj *obj; + obj = pdf_dict_gets(dict, "Resources"); if (pdf_resources_use_blending(ctx, obj)) return 1; - obj = fz_dict_gets(dict, "ExtGState"); + obj = pdf_dict_gets(dict, "ExtGState"); return pdf_extgstate_uses_blending(ctx, obj); } static int -pdf_xobject_uses_blending(fz_context *ctx, fz_obj *dict) +pdf_xobject_uses_blending(fz_context *ctx, pdf_obj *dict) { - fz_obj *obj = fz_dict_gets(dict, "Resources"); + pdf_obj *obj = pdf_dict_gets(dict, "Resources"); return pdf_resources_use_blending(ctx, obj); } static int -pdf_resources_use_blending(fz_context *ctx, fz_obj *rdb) +pdf_resources_use_blending(fz_context *ctx, pdf_obj *rdb) { - fz_obj *obj; + pdf_obj *obj; int i, n, useBM = 0; if (!rdb) return 0; /* Have we been here before and stashed an answer? */ - obj = fz_dict_gets(rdb, ".useBM"); + obj = pdf_dict_gets(rdb, ".useBM"); if (obj) - return fz_to_bool(obj); + return pdf_to_bool(obj); /* stop on cyclic resource dependencies */ - if (fz_dict_mark(rdb)) + if (pdf_dict_mark(rdb)) return 0; fz_try(ctx) { - obj = fz_dict_gets(rdb, "ExtGState"); - n = fz_dict_len(obj); + obj = pdf_dict_gets(rdb, "ExtGState"); + n = pdf_dict_len(obj); for (i = 0; i < n; i++) - if (pdf_extgstate_uses_blending(ctx, fz_dict_get_val(obj, i))) + if (pdf_extgstate_uses_blending(ctx, pdf_dict_get_val(obj, i))) goto found; - obj = fz_dict_gets(rdb, "Pattern"); - n = fz_dict_len(obj); + obj = pdf_dict_gets(rdb, "Pattern"); + n = pdf_dict_len(obj); for (i = 0; i < n; i++) - if (pdf_pattern_uses_blending(ctx, fz_dict_get_val(obj, i))) + if (pdf_pattern_uses_blending(ctx, pdf_dict_get_val(obj, i))) goto found; - obj = fz_dict_gets(rdb, "XObject"); - n = fz_dict_len(obj); + obj = pdf_dict_gets(rdb, "XObject"); + n = pdf_dict_len(obj); for (i = 0; i < n; i++) - if (pdf_xobject_uses_blending(ctx, fz_dict_get_val(obj, i))) + if (pdf_xobject_uses_blending(ctx, pdf_dict_get_val(obj, i))) goto found; if (0) { @@ -227,10 +227,10 @@ found: } fz_catch(ctx) { - fz_dict_unmark(rdb); + pdf_dict_unmark(rdb); fz_rethrow(ctx); } - fz_dict_unmark(rdb); + pdf_dict_unmark(rdb); put_marker_bool(ctx, rdb, ".useBM", useBM); return useBM; @@ -239,7 +239,7 @@ found: /* we need to combine all sub-streams into one for the content stream interpreter */ static fz_buffer * -pdf_load_page_contents_array(pdf_document *xref, fz_obj *list) +pdf_load_page_contents_array(pdf_document *xref, pdf_obj *list) { fz_buffer *big; fz_buffer *one; @@ -248,14 +248,14 @@ pdf_load_page_contents_array(pdf_document *xref, fz_obj *list) big = fz_new_buffer(ctx, 32 * 1024); - n = fz_array_len(list); + n = pdf_array_len(list); fz_var(i); /* Workaround Mac compiler bug */ for (i = 0; i < n; i++) { - fz_obj *stm = fz_array_get(list, i); + pdf_obj *stm = pdf_array_get(list, i); fz_try(ctx) { - one = pdf_load_stream(xref, fz_to_num(stm), fz_to_gen(stm)); + one = pdf_load_stream(xref, pdf_to_num(stm), pdf_to_gen(stm)); } fz_catch(ctx) { @@ -277,24 +277,25 @@ pdf_load_page_contents_array(pdf_document *xref, fz_obj *list) fz_drop_buffer(ctx, big); fz_throw(ctx, "cannot load content stream"); } + fz_trim_buffer(ctx, big); return big; } static fz_buffer * -pdf_load_page_contents(pdf_document *xref, fz_obj *obj) +pdf_load_page_contents(pdf_document *xref, pdf_obj *obj) { fz_context *ctx = xref->ctx; - if (fz_is_array(obj)) + if (pdf_is_array(obj)) { return pdf_load_page_contents_array(xref, obj); /* RJW: "cannot load content stream array" */ } - else if (pdf_is_stream(xref, fz_to_num(obj), fz_to_gen(obj))) + else if (pdf_is_stream(xref, pdf_to_num(obj), pdf_to_gen(obj))) { - return pdf_load_stream(xref, fz_to_num(obj), fz_to_gen(obj)); - /* RJW: "cannot load content stream (%d 0 R)", fz_to_num(obj) */ + return pdf_load_stream(xref, pdf_to_num(obj), pdf_to_gen(obj)); + /* RJW: "cannot load content stream (%d 0 R)", pdf_to_num(obj) */ } fz_warn(ctx, "page contents missing, leaving page blank"); @@ -307,7 +308,7 @@ pdf_load_page(pdf_document *xref, int number) fz_context *ctx = xref->ctx; pdf_page *page; pdf_annot *annot; - fz_obj *pageobj, *pageref, *obj; + pdf_obj *pageobj, *pageref, *obj; fz_rect mediabox, cropbox, realbox; fz_matrix ctm; @@ -325,7 +326,7 @@ pdf_load_page(pdf_document *xref, int number) page->links = NULL; page->annots = NULL; - mediabox = pdf_to_rect(ctx, fz_dict_gets(pageobj, "MediaBox")); + mediabox = pdf_to_rect(ctx, pdf_dict_gets(pageobj, "MediaBox")); if (fz_is_empty_rect(mediabox)) { fz_warn(ctx, "cannot find page size for page %d", number + 1); @@ -335,7 +336,7 @@ pdf_load_page(pdf_document *xref, int number) mediabox.y1 = 792; } - cropbox = pdf_to_rect(ctx, fz_dict_gets(pageobj, "CropBox")); + cropbox = pdf_to_rect(ctx, pdf_dict_gets(pageobj, "CropBox")); if (!fz_is_empty_rect(cropbox)) mediabox = fz_intersect_rect(mediabox, cropbox); @@ -350,24 +351,24 @@ pdf_load_page(pdf_document *xref, int number) page->mediabox = fz_unit_rect; } - page->rotate = fz_to_int(fz_dict_gets(pageobj, "Rotate")); + page->rotate = pdf_to_int(pdf_dict_gets(pageobj, "Rotate")); ctm = fz_concat(fz_rotate(-page->rotate), fz_scale(1, -1)); realbox = fz_transform_rect(ctm, page->mediabox); page->ctm = fz_concat(ctm, fz_translate(-realbox.x0, -realbox.y0)); - obj = fz_dict_gets(pageobj, "Annots"); + obj = pdf_dict_gets(pageobj, "Annots"); if (obj) { page->links = pdf_load_link_annots(xref, obj, page->ctm); page->annots = pdf_load_annots(xref, obj); } - page->resources = fz_dict_gets(pageobj, "Resources"); + page->resources = pdf_dict_gets(pageobj, "Resources"); if (page->resources) - fz_keep_obj(page->resources); + pdf_keep_obj(page->resources); - obj = fz_dict_gets(pageobj, "Contents"); + obj = pdf_dict_gets(pageobj, "Contents"); fz_try(ctx) { page->contents = pdf_load_page_contents(xref, obj); @@ -382,7 +383,7 @@ pdf_load_page(pdf_document *xref, int number) fz_catch(ctx) { pdf_free_page(xref, page); - fz_throw(ctx, "cannot load page %d contents (%d 0 R)", number + 1, fz_to_num(pageref)); + fz_throw(ctx, "cannot load page %d contents (%d 0 R)", number + 1, pdf_to_num(pageref)); } return page; @@ -408,7 +409,7 @@ void pdf_free_page(pdf_document *xref, pdf_page *page) { if (page->resources) - fz_drop_obj(page->resources); + pdf_drop_obj(page->resources); if (page->contents) fz_drop_buffer(xref->ctx, page->contents); if (page->links) diff --git a/pdf/pdf_parse.c b/pdf/pdf_parse.c index 220eb30c..fe9db368 100644 --- a/pdf/pdf_parse.c +++ b/pdf/pdf_parse.c @@ -1,14 +1,14 @@ -#include "fitz.h" -#include "mupdf.h" +#include "fitz-internal.h" +#include "mupdf-internal.h" fz_rect -pdf_to_rect(fz_context *ctx, fz_obj *array) +pdf_to_rect(fz_context *ctx, pdf_obj *array) { fz_rect r; - float a = fz_to_real(fz_array_get(array, 0)); - float b = fz_to_real(fz_array_get(array, 1)); - float c = fz_to_real(fz_array_get(array, 2)); - float d = fz_to_real(fz_array_get(array, 3)); + float a = pdf_to_real(pdf_array_get(array, 0)); + float b = pdf_to_real(pdf_array_get(array, 1)); + float c = pdf_to_real(pdf_array_get(array, 2)); + float d = pdf_to_real(pdf_array_get(array, 3)); r.x0 = MIN(a, c); r.y0 = MIN(b, d); r.x1 = MAX(a, c); @@ -17,25 +17,25 @@ pdf_to_rect(fz_context *ctx, fz_obj *array) } fz_matrix -pdf_to_matrix(fz_context *ctx, fz_obj *array) +pdf_to_matrix(fz_context *ctx, pdf_obj *array) { fz_matrix m; - m.a = fz_to_real(fz_array_get(array, 0)); - m.b = fz_to_real(fz_array_get(array, 1)); - m.c = fz_to_real(fz_array_get(array, 2)); - m.d = fz_to_real(fz_array_get(array, 3)); - m.e = fz_to_real(fz_array_get(array, 4)); - m.f = fz_to_real(fz_array_get(array, 5)); + m.a = pdf_to_real(pdf_array_get(array, 0)); + m.b = pdf_to_real(pdf_array_get(array, 1)); + m.c = pdf_to_real(pdf_array_get(array, 2)); + m.d = pdf_to_real(pdf_array_get(array, 3)); + m.e = pdf_to_real(pdf_array_get(array, 4)); + m.f = pdf_to_real(pdf_array_get(array, 5)); return m; } /* Convert Unicode/PdfDocEncoding string into utf-8 */ char * -pdf_to_utf8(fz_context *ctx, fz_obj *src) +pdf_to_utf8(fz_context *ctx, pdf_obj *src) { - unsigned char *srcptr = (unsigned char *) fz_to_str_buf(src); + unsigned char *srcptr = (unsigned char *) pdf_to_str_buf(src); char *dstptr, *dst; - int srclen = fz_to_str_len(src); + int srclen = pdf_to_str_len(src); int dstlen = 0; int ucs; int i; @@ -45,7 +45,7 @@ pdf_to_utf8(fz_context *ctx, fz_obj *src) for (i = 2; i + 1 < srclen; i += 2) { ucs = srcptr[i] << 8 | srcptr[i+1]; - dstlen += runelen(ucs); + dstlen += fz_runelen(ucs); } dstptr = dst = fz_malloc(ctx, dstlen + 1); @@ -53,7 +53,7 @@ pdf_to_utf8(fz_context *ctx, fz_obj *src) for (i = 2; i + 1 < srclen; i += 2) { ucs = srcptr[i] << 8 | srcptr[i+1]; - dstptr += runetochar(dstptr, &ucs); + dstptr += fz_runetochar(dstptr, ucs); } } else if (srclen >= 2 && srcptr[0] == 255 && srcptr[1] == 254) @@ -61,7 +61,7 @@ pdf_to_utf8(fz_context *ctx, fz_obj *src) for (i = 2; i + 1 < srclen; i += 2) { ucs = srcptr[i] | srcptr[i+1] << 8; - dstlen += runelen(ucs); + dstlen += fz_runelen(ucs); } dstptr = dst = fz_malloc(ctx, dstlen + 1); @@ -69,20 +69,20 @@ pdf_to_utf8(fz_context *ctx, fz_obj *src) for (i = 2; i + 1 < srclen; i += 2) { ucs = srcptr[i] | srcptr[i+1] << 8; - dstptr += runetochar(dstptr, &ucs); + dstptr += fz_runetochar(dstptr, ucs); } } else { for (i = 0; i < srclen; i++) - dstlen += runelen(pdf_doc_encoding[srcptr[i]]); + dstlen += fz_runelen(pdf_doc_encoding[srcptr[i]]); dstptr = dst = fz_malloc(ctx, dstlen + 1); for (i = 0; i < srclen; i++) { ucs = pdf_doc_encoding[srcptr[i]]; - dstptr += runetochar(dstptr, &ucs); + dstptr += fz_runetochar(dstptr, ucs); } } @@ -92,11 +92,11 @@ pdf_to_utf8(fz_context *ctx, fz_obj *src) /* Convert Unicode/PdfDocEncoding string into ucs-2 */ unsigned short * -pdf_to_ucs2(fz_context *ctx, fz_obj *src) +pdf_to_ucs2(fz_context *ctx, pdf_obj *src) { - unsigned char *srcptr = (unsigned char *) fz_to_str_buf(src); + unsigned char *srcptr = (unsigned char *) pdf_to_str_buf(src); unsigned short *dstptr, *dst; - int srclen = fz_to_str_len(src); + int srclen = pdf_to_str_len(src); int i; if (srclen >= 2 && srcptr[0] == 254 && srcptr[1] == 255) @@ -161,50 +161,49 @@ pdf_from_ucs2(fz_context *ctx, unsigned short *src) return docstr; } -fz_obj * -pdf_to_utf8_name(fz_context *ctx, fz_obj *src) +pdf_obj * +pdf_to_utf8_name(fz_context *ctx, pdf_obj *src) { char *buf = pdf_to_utf8(ctx, src); - fz_obj *dst = fz_new_name(ctx, buf); + pdf_obj *dst = fz_new_name(ctx, buf); fz_free(ctx, buf); return dst; } -fz_obj * -pdf_parse_array(pdf_document *xref, fz_stream *file, char *buf, int cap) +pdf_obj * +pdf_parse_array(pdf_document *xref, fz_stream *file, pdf_lexbuf *buf) { - fz_obj *ary = NULL; - fz_obj *obj = NULL; + pdf_obj *ary = NULL; + pdf_obj *obj = NULL; int a = 0, b = 0, n = 0; int tok; - int len; fz_context *ctx = file->ctx; - fz_obj *op; + pdf_obj *op; fz_var(obj); - ary = fz_new_array(ctx, 4); + ary = pdf_new_array(ctx, 4); fz_try(ctx) { while (1) { - tok = pdf_lex(file, buf, cap, &len); + tok = pdf_lex(file, buf); if (tok != PDF_TOK_INT && tok != PDF_TOK_R) { if (n > 0) { - obj = fz_new_int(ctx, a); - fz_array_push(ary, obj); - fz_drop_obj(obj); + obj = pdf_new_int(ctx, a); + pdf_array_push(ary, obj); + pdf_drop_obj(obj); obj = NULL; } if (n > 1) { - obj = fz_new_int(ctx, b); - fz_array_push(ary, obj); - fz_drop_obj(obj); + obj = pdf_new_int(ctx, b); + pdf_array_push(ary, obj); + pdf_drop_obj(obj); obj = NULL; } n = 0; @@ -212,9 +211,9 @@ pdf_parse_array(pdf_document *xref, fz_stream *file, char *buf, int cap) if (tok == PDF_TOK_INT && n == 2) { - obj = fz_new_int(ctx, a); - fz_array_push(ary, obj); - fz_drop_obj(obj); + obj = pdf_new_int(ctx, a); + pdf_array_push(ary, obj); + pdf_drop_obj(obj); obj = NULL; a = b; n --; @@ -228,70 +227,70 @@ pdf_parse_array(pdf_document *xref, fz_stream *file, char *buf, int cap) case PDF_TOK_INT: if (n == 0) - a = atoi(buf); + a = buf->i; if (n == 1) - b = atoi(buf); + b = buf->i; n ++; break; case PDF_TOK_R: if (n != 2) fz_throw(ctx, "cannot parse indirect reference in array"); - obj = fz_new_indirect(ctx, a, b, xref); - fz_array_push(ary, obj); - fz_drop_obj(obj); + obj = pdf_new_indirect(ctx, a, b, xref); + pdf_array_push(ary, obj); + pdf_drop_obj(obj); obj = NULL; n = 0; break; case PDF_TOK_OPEN_ARRAY: - obj = pdf_parse_array(xref, file, buf, cap); - fz_array_push(ary, obj); - fz_drop_obj(obj); + obj = pdf_parse_array(xref, file, buf); + pdf_array_push(ary, obj); + pdf_drop_obj(obj); obj = NULL; break; case PDF_TOK_OPEN_DICT: - obj = pdf_parse_dict(xref, file, buf, cap); - fz_array_push(ary, obj); - fz_drop_obj(obj); + obj = pdf_parse_dict(xref, file, buf); + pdf_array_push(ary, obj); + pdf_drop_obj(obj); obj = NULL; break; case PDF_TOK_NAME: - obj = fz_new_name(ctx, buf); - fz_array_push(ary, obj); - fz_drop_obj(obj); + obj = fz_new_name(ctx, buf->scratch); + pdf_array_push(ary, obj); + pdf_drop_obj(obj); obj = NULL; break; case PDF_TOK_REAL: - obj = fz_new_real(ctx, fz_atof(buf)); - fz_array_push(ary, obj); - fz_drop_obj(obj); + obj = pdf_new_real(ctx, buf->f); + pdf_array_push(ary, obj); + pdf_drop_obj(obj); obj = NULL; break; case PDF_TOK_STRING: - obj = fz_new_string(ctx, buf, len); - fz_array_push(ary, obj); - fz_drop_obj(obj); + obj = pdf_new_string(ctx, buf->scratch, buf->len); + pdf_array_push(ary, obj); + pdf_drop_obj(obj); obj = NULL; break; case PDF_TOK_TRUE: - obj = fz_new_bool(ctx, 1); - fz_array_push(ary, obj); - fz_drop_obj(obj); + obj = pdf_new_bool(ctx, 1); + pdf_array_push(ary, obj); + pdf_drop_obj(obj); obj = NULL; break; case PDF_TOK_FALSE: - obj = fz_new_bool(ctx, 0); - fz_array_push(ary, obj); - fz_drop_obj(obj); + obj = pdf_new_bool(ctx, 0); + pdf_array_push(ary, obj); + pdf_drop_obj(obj); obj = NULL; break; case PDF_TOK_NULL: - obj = fz_new_null(ctx); - fz_array_push(ary, obj); - fz_drop_obj(obj); + obj = pdf_new_null(ctx); + pdf_array_push(ary, obj); + pdf_drop_obj(obj); obj = NULL; break; @@ -304,89 +303,87 @@ end: } fz_catch(ctx) { - fz_drop_obj(obj); - fz_drop_obj(ary); + pdf_drop_obj(obj); + pdf_drop_obj(ary); fz_throw(ctx, "cannot parse array"); } return op; } -fz_obj * -pdf_parse_dict(pdf_document *xref, fz_stream *file, char *buf, int cap) +pdf_obj * +pdf_parse_dict(pdf_document *xref, fz_stream *file, pdf_lexbuf *buf) { - fz_obj *dict = NULL; - fz_obj *key = NULL; - fz_obj *val = NULL; + pdf_obj *dict; + pdf_obj *key = NULL; + pdf_obj *val = NULL; int tok; - int len; int a, b; fz_context *ctx = file->ctx; - fz_var(dict); + dict = pdf_new_dict(ctx, 8); + fz_var(key); fz_var(val); - dict = fz_new_dict(ctx, 8); - fz_try(ctx) { while (1) { - tok = pdf_lex(file, buf, cap, &len); + tok = pdf_lex(file, buf); skip: if (tok == PDF_TOK_CLOSE_DICT) break; /* for BI .. ID .. EI in content streams */ - if (tok == PDF_TOK_KEYWORD && !strcmp(buf, "ID")) + if (tok == PDF_TOK_KEYWORD && !strcmp(buf->scratch, "ID")) break; if (tok != PDF_TOK_NAME) fz_throw(ctx, "invalid key in dict"); - key = fz_new_name(ctx, buf); + key = fz_new_name(ctx, buf->scratch); - tok = pdf_lex(file, buf, cap, &len); + tok = pdf_lex(file, buf); switch (tok) { case PDF_TOK_OPEN_ARRAY: - val = pdf_parse_array(xref, file, buf, cap); + val = pdf_parse_array(xref, file, buf); break; case PDF_TOK_OPEN_DICT: - val = pdf_parse_dict(xref, file, buf, cap); + val = pdf_parse_dict(xref, file, buf); break; - case PDF_TOK_NAME: val = fz_new_name(ctx, buf); break; - case PDF_TOK_REAL: val = fz_new_real(ctx, fz_atof(buf)); break; - case PDF_TOK_STRING: val = fz_new_string(ctx, buf, len); break; - case PDF_TOK_TRUE: val = fz_new_bool(ctx, 1); break; - case PDF_TOK_FALSE: val = fz_new_bool(ctx, 0); break; - case PDF_TOK_NULL: val = fz_new_null(ctx); break; + case PDF_TOK_NAME: val = fz_new_name(ctx, buf->scratch); break; + case PDF_TOK_REAL: val = pdf_new_real(ctx, buf->f); break; + case PDF_TOK_STRING: val = pdf_new_string(ctx, buf->scratch, buf->len); break; + case PDF_TOK_TRUE: val = pdf_new_bool(ctx, 1); break; + case PDF_TOK_FALSE: val = pdf_new_bool(ctx, 0); break; + case PDF_TOK_NULL: val = pdf_new_null(ctx); break; case PDF_TOK_INT: /* 64-bit to allow for numbers > INT_MAX and overflow */ - a = (int) strtoll(buf, 0, 10); - tok = pdf_lex(file, buf, cap, &len); + a = buf->i; + tok = pdf_lex(file, buf); if (tok == PDF_TOK_CLOSE_DICT || tok == PDF_TOK_NAME || - (tok == PDF_TOK_KEYWORD && !strcmp(buf, "ID"))) + (tok == PDF_TOK_KEYWORD && !strcmp(buf->scratch, "ID"))) { - val = fz_new_int(ctx, a); + val = pdf_new_int(ctx, a); fz_dict_put(dict, key, val); - fz_drop_obj(val); + pdf_drop_obj(val); val = NULL; - fz_drop_obj(key); + pdf_drop_obj(key); key = NULL; goto skip; } if (tok == PDF_TOK_INT) { - b = atoi(buf); - tok = pdf_lex(file, buf, cap, &len); + b = buf->i; + tok = pdf_lex(file, buf); if (tok == PDF_TOK_R) { - val = fz_new_indirect(ctx, a, b, xref); + val = pdf_new_indirect(ctx, a, b, xref); break; } } @@ -397,129 +394,127 @@ pdf_parse_dict(pdf_document *xref, fz_stream *file, char *buf, int cap) } fz_dict_put(dict, key, val); - fz_drop_obj(val); + pdf_drop_obj(val); val = NULL; - fz_drop_obj(key); + pdf_drop_obj(key); key = NULL; } } fz_catch(ctx) { - fz_drop_obj(dict); - fz_drop_obj(key); - fz_drop_obj(val); + pdf_drop_obj(dict); + pdf_drop_obj(key); + pdf_drop_obj(val); fz_throw(ctx, "cannot parse dict"); } return dict; } -fz_obj * -pdf_parse_stm_obj(pdf_document *xref, fz_stream *file, char *buf, int cap) +pdf_obj * +pdf_parse_stm_obj(pdf_document *xref, fz_stream *file, pdf_lexbuf *buf) { int tok; - int len; fz_context *ctx = file->ctx; - tok = pdf_lex(file, buf, cap, &len); + tok = pdf_lex(file, buf); /* RJW: "cannot parse token in object stream") */ switch (tok) { case PDF_TOK_OPEN_ARRAY: - return pdf_parse_array(xref, file, buf, cap); + return pdf_parse_array(xref, file, buf); /* RJW: "cannot parse object stream" */ case PDF_TOK_OPEN_DICT: - return pdf_parse_dict(xref, file, buf, cap); + return pdf_parse_dict(xref, file, buf); /* RJW: "cannot parse object stream" */ - case PDF_TOK_NAME: return fz_new_name(ctx, buf); break; - case PDF_TOK_REAL: return fz_new_real(ctx, fz_atof(buf)); break; - case PDF_TOK_STRING: return fz_new_string(ctx, buf, len); break; - case PDF_TOK_TRUE: return fz_new_bool(ctx, 1); break; - case PDF_TOK_FALSE: return fz_new_bool(ctx, 0); break; - case PDF_TOK_NULL: return fz_new_null(ctx); break; - case PDF_TOK_INT: return fz_new_int(ctx, atoi(buf)); break; + case PDF_TOK_NAME: return fz_new_name(ctx, buf->scratch); break; + case PDF_TOK_REAL: return pdf_new_real(ctx, buf->f); break; + case PDF_TOK_STRING: return pdf_new_string(ctx, buf->scratch, buf->len); break; + case PDF_TOK_TRUE: return pdf_new_bool(ctx, 1); break; + case PDF_TOK_FALSE: return pdf_new_bool(ctx, 0); break; + case PDF_TOK_NULL: return pdf_new_null(ctx); break; + case PDF_TOK_INT: return pdf_new_int(ctx, buf->i); break; default: fz_throw(ctx, "unknown token in object stream"); } return NULL; /* Stupid MSVC */ } -fz_obj * +pdf_obj * pdf_parse_ind_obj(pdf_document *xref, - fz_stream *file, char *buf, int cap, + fz_stream *file, pdf_lexbuf *buf, int *onum, int *ogen, int *ostmofs) { - fz_obj *obj = NULL; + pdf_obj *obj = NULL; int num = 0, gen = 0, stm_ofs; int tok; - int len; int a, b; fz_context *ctx = file->ctx; fz_var(obj); - tok = pdf_lex(file, buf, cap, &len); + tok = pdf_lex(file, buf); /* RJW: cannot parse indirect object (%d %d R)", num, gen */ if (tok != PDF_TOK_INT) fz_throw(ctx, "expected object number (%d %d R)", num, gen); - num = atoi(buf); + num = buf->i; - tok = pdf_lex(file, buf, cap, &len); + tok = pdf_lex(file, buf); /* RJW: "cannot parse indirect object (%d %d R)", num, gen */ if (tok != PDF_TOK_INT) fz_throw(ctx, "expected generation number (%d %d R)", num, gen); - gen = atoi(buf); + gen = buf->i; - tok = pdf_lex(file, buf, cap, &len); + tok = pdf_lex(file, buf); /* RJW: "cannot parse indirect object (%d %d R)", num, gen */ if (tok != PDF_TOK_OBJ) fz_throw(ctx, "expected 'obj' keyword (%d %d R)", num, gen); - tok = pdf_lex(file, buf, cap, &len); + tok = pdf_lex(file, buf); /* RJW: "cannot parse indirect object (%d %d R)", num, gen */ switch (tok) { case PDF_TOK_OPEN_ARRAY: - obj = pdf_parse_array(xref, file, buf, cap); + obj = pdf_parse_array(xref, file, buf); /* RJW: "cannot parse indirect object (%d %d R)", num, gen */ break; case PDF_TOK_OPEN_DICT: - obj = pdf_parse_dict(xref, file, buf, cap); + obj = pdf_parse_dict(xref, file, buf); /* RJW: "cannot parse indirect object (%d %d R)", num, gen */ break; - case PDF_TOK_NAME: obj = fz_new_name(ctx, buf); break; - case PDF_TOK_REAL: obj = fz_new_real(ctx, fz_atof(buf)); break; - case PDF_TOK_STRING: obj = fz_new_string(ctx, buf, len); break; - case PDF_TOK_TRUE: obj = fz_new_bool(ctx, 1); break; - case PDF_TOK_FALSE: obj = fz_new_bool(ctx, 0); break; - case PDF_TOK_NULL: obj = fz_new_null(ctx); break; + case PDF_TOK_NAME: obj = fz_new_name(ctx, buf->scratch); break; + case PDF_TOK_REAL: obj = pdf_new_real(ctx, buf->f); break; + case PDF_TOK_STRING: obj = pdf_new_string(ctx, buf->scratch, buf->len); break; + case PDF_TOK_TRUE: obj = pdf_new_bool(ctx, 1); break; + case PDF_TOK_FALSE: obj = pdf_new_bool(ctx, 0); break; + case PDF_TOK_NULL: obj = pdf_new_null(ctx); break; case PDF_TOK_INT: - a = atoi(buf); - tok = pdf_lex(file, buf, cap, &len); + a = buf->i; + tok = pdf_lex(file, buf); /* "cannot parse indirect object (%d %d R)", num, gen */ if (tok == PDF_TOK_STREAM || tok == PDF_TOK_ENDOBJ) { - obj = fz_new_int(ctx, a); + obj = pdf_new_int(ctx, a); goto skip; } if (tok == PDF_TOK_INT) { - b = atoi(buf); - tok = pdf_lex(file, buf, cap, &len); + b = buf->i; + tok = pdf_lex(file, buf); /* RJW: "cannot parse indirect object (%d %d R)", num, gen); */ if (tok == PDF_TOK_R) { - obj = fz_new_indirect(ctx, a, b, xref); + obj = pdf_new_indirect(ctx, a, b, xref); break; } } fz_throw(ctx, "expected 'R' keyword (%d %d R)", num, gen); case PDF_TOK_ENDOBJ: - obj = fz_new_null(ctx); + obj = pdf_new_null(ctx); goto skip; default: @@ -528,11 +523,11 @@ pdf_parse_ind_obj(pdf_document *xref, fz_try(ctx) { - tok = pdf_lex(file, buf, cap, &len); + tok = pdf_lex(file, buf); } fz_catch(ctx) { - fz_drop_obj(obj); + pdf_drop_obj(obj); fz_throw(ctx, "cannot parse indirect object (%d %d R)", num, gen); } diff --git a/pdf/pdf_pattern.c b/pdf/pdf_pattern.c index 9ffbee02..14175670 100644 --- a/pdf/pdf_pattern.c +++ b/pdf/pdf_pattern.c @@ -1,5 +1,5 @@ -#include "fitz.h" -#include "mupdf.h" +#include "fitz-internal.h" +#include "mupdf-internal.h" pdf_pattern * pdf_keep_pattern(fz_context *ctx, pdf_pattern *pat) @@ -19,7 +19,7 @@ pdf_free_pattern_imp(fz_context *ctx, fz_storable *pat_) pdf_pattern *pat = (pdf_pattern *)pat_; if (pat->resources) - fz_drop_obj(pat->resources); + pdf_drop_obj(pat->resources); if (pat->contents) fz_drop_buffer(ctx, pat->contents); fz_free(ctx, pat); @@ -34,13 +34,13 @@ pdf_pattern_size(pdf_pattern *pat) } pdf_pattern * -pdf_load_pattern(pdf_document *xref, fz_obj *dict) +pdf_load_pattern(pdf_document *xref, pdf_obj *dict) { pdf_pattern *pat; - fz_obj *obj; + pdf_obj *obj; fz_context *ctx = xref->ctx; - if ((pat = fz_find_item(ctx, pdf_free_pattern_imp, dict))) + if ((pat = pdf_find_item(ctx, pdf_free_pattern_imp, dict))) { return pat; } @@ -51,34 +51,34 @@ pdf_load_pattern(pdf_document *xref, fz_obj *dict) pat->contents = NULL; /* Store pattern now, to avoid possible recursion if objects refer back to this one */ - fz_store_item(ctx, dict, pat, pdf_pattern_size(pat)); + pdf_store_item(ctx, dict, pat, pdf_pattern_size(pat)); - pat->ismask = fz_to_int(fz_dict_gets(dict, "PaintType")) == 2; - pat->xstep = fz_to_real(fz_dict_gets(dict, "XStep")); - pat->ystep = fz_to_real(fz_dict_gets(dict, "YStep")); + pat->ismask = pdf_to_int(pdf_dict_gets(dict, "PaintType")) == 2; + pat->xstep = pdf_to_real(pdf_dict_gets(dict, "XStep")); + pat->ystep = pdf_to_real(pdf_dict_gets(dict, "YStep")); - obj = fz_dict_gets(dict, "BBox"); + obj = pdf_dict_gets(dict, "BBox"); pat->bbox = pdf_to_rect(ctx, obj); - obj = fz_dict_gets(dict, "Matrix"); + obj = pdf_dict_gets(dict, "Matrix"); if (obj) pat->matrix = pdf_to_matrix(ctx, obj); else pat->matrix = fz_identity; - pat->resources = fz_dict_gets(dict, "Resources"); + pat->resources = pdf_dict_gets(dict, "Resources"); if (pat->resources) - fz_keep_obj(pat->resources); + pdf_keep_obj(pat->resources); fz_try(ctx) { - pat->contents = pdf_load_stream(xref, fz_to_num(dict), fz_to_gen(dict)); + pat->contents = pdf_load_stream(xref, pdf_to_num(dict), pdf_to_gen(dict)); } fz_catch(ctx) { - fz_remove_item(ctx, pdf_free_pattern_imp, dict); + pdf_remove_item(ctx, pdf_free_pattern_imp, dict); pdf_drop_pattern(ctx, pat); - fz_throw(ctx, "cannot load pattern stream (%d %d R)", fz_to_num(dict), fz_to_gen(dict)); + fz_throw(ctx, "cannot load pattern stream (%d %d R)", pdf_to_num(dict), pdf_to_gen(dict)); } return pat; } diff --git a/pdf/pdf_repair.c b/pdf/pdf_repair.c index 0dc0e132..fda1e6b5 100644 --- a/pdf/pdf_repair.c +++ b/pdf/pdf_repair.c @@ -1,5 +1,5 @@ -#include "fitz.h" -#include "mupdf.h" +#include "fitz-internal.h" +#include "mupdf-internal.h" /* Scan file for objects and reconstruct xref table */ @@ -13,11 +13,10 @@ struct entry }; static void -pdf_repair_obj(fz_stream *file, char *buf, int cap, int *stmofsp, int *stmlenp, fz_obj **encrypt, fz_obj **id) +pdf_repair_obj(fz_stream *file, pdf_lexbuf *buf, int *stmofsp, int *stmlenp, pdf_obj **encrypt, pdf_obj **id) { int tok; int stm_len; - int len; int n; fz_context *ctx = file->ctx; @@ -26,16 +25,16 @@ pdf_repair_obj(fz_stream *file, char *buf, int cap, int *stmofsp, int *stmlenp, stm_len = 0; - tok = pdf_lex(file, buf, cap, &len); + tok = pdf_lex(file, buf); /* RJW: "cannot parse object" */ if (tok == PDF_TOK_OPEN_DICT) { - fz_obj *dict, *obj; + pdf_obj *dict, *obj; /* Send NULL xref so we don't try to resolve references */ fz_try(ctx) { - dict = pdf_parse_dict(NULL, file, buf, cap); + dict = pdf_parse_dict(NULL, file, buf); } fz_catch(ctx) { @@ -43,34 +42,34 @@ pdf_repair_obj(fz_stream *file, char *buf, int cap, int *stmofsp, int *stmlenp, if (file->eof) fz_throw(ctx, "broken object at EOF ignored"); /* Silently swallow the error */ - dict = fz_new_dict(ctx, 2); + dict = pdf_new_dict(ctx, 2); } - obj = fz_dict_gets(dict, "Type"); - if (fz_is_name(obj) && !strcmp(fz_to_name(obj), "XRef")) + obj = pdf_dict_gets(dict, "Type"); + if (pdf_is_name(obj) && !strcmp(pdf_to_name(obj), "XRef")) { - obj = fz_dict_gets(dict, "Encrypt"); + obj = pdf_dict_gets(dict, "Encrypt"); if (obj) { if (*encrypt) - fz_drop_obj(*encrypt); - *encrypt = fz_keep_obj(obj); + pdf_drop_obj(*encrypt); + *encrypt = pdf_keep_obj(obj); } - obj = fz_dict_gets(dict, "ID"); + obj = pdf_dict_gets(dict, "ID"); if (obj) { if (*id) - fz_drop_obj(*id); - *id = fz_keep_obj(obj); + pdf_drop_obj(*id); + *id = pdf_keep_obj(obj); } } - obj = fz_dict_gets(dict, "Length"); - if (!fz_is_indirect(obj) && fz_is_int(obj)) - stm_len = fz_to_int(obj); + obj = pdf_dict_gets(dict, "Length"); + if (!pdf_is_indirect(obj) && pdf_is_int(obj)) + stm_len = pdf_to_int(obj); - fz_drop_obj(dict); + pdf_drop_obj(dict); } while ( tok != PDF_TOK_STREAM && @@ -79,13 +78,13 @@ pdf_repair_obj(fz_stream *file, char *buf, int cap, int *stmofsp, int *stmlenp, tok != PDF_TOK_EOF && tok != PDF_TOK_INT ) { - tok = pdf_lex(file, buf, cap, &len); + tok = pdf_lex(file, buf); /* RJW: "cannot scan for endobj or stream token" */ } if (tok == PDF_TOK_INT) { - while (len-- > 0) + while (buf->len-- > 0) fz_unread_byte(file); } else if (tok == PDF_TOK_STREAM) @@ -106,7 +105,7 @@ pdf_repair_obj(fz_stream *file, char *buf, int cap, int *stmofsp, int *stmlenp, fz_seek(file, *stmofsp + stm_len, 0); fz_try(ctx) { - tok = pdf_lex(file, buf, cap, &len); + tok = pdf_lex(file, buf); } fz_catch(ctx) { @@ -117,23 +116,23 @@ pdf_repair_obj(fz_stream *file, char *buf, int cap, int *stmofsp, int *stmlenp, fz_seek(file, *stmofsp, 0); } - n = fz_read(file, (unsigned char *) buf, 9); + n = fz_read(file, (unsigned char *) buf->scratch, 9); if (n < 0) fz_throw(ctx, "cannot read from file"); - while (memcmp(buf, "endstream", 9) != 0) + while (memcmp(buf->scratch, "endstream", 9) != 0) { c = fz_read_byte(file); if (c == EOF) break; - memmove(buf, buf + 1, 8); - buf[8] = c; + memmove(&buf->scratch[0], &buf->scratch[1], 8); + buf->scratch[8] = c; } *stmlenp = fz_tell(file) - *stmofsp - 9; atobjend: - tok = pdf_lex(file, buf, cap, &len); + tok = pdf_lex(file, buf); /* RJW: "cannot scan for endobj token" */ if (tok != PDF_TOK_ENDOBJ) fz_warn(ctx, "object missing 'endobj' token"); @@ -143,43 +142,45 @@ atobjend: static void pdf_repair_obj_stm(pdf_document *xref, int num, int gen) { - fz_obj *obj; + pdf_obj *obj; fz_stream *stm = NULL; int tok; int i, n, count; - char buf[256]; fz_context *ctx = xref->ctx; + pdf_lexbuf buf; fz_var(stm); + buf.size = PDF_LEXBUF_SMALL; + fz_try(ctx) { obj = pdf_load_object(xref, num, gen); - count = fz_to_int(fz_dict_gets(obj, "N")); + count = pdf_to_int(pdf_dict_gets(obj, "N")); - fz_drop_obj(obj); + pdf_drop_obj(obj); stm = pdf_open_stream(xref, num, gen); for (i = 0; i < count; i++) { - tok = pdf_lex(stm, buf, sizeof buf, &n); + tok = pdf_lex(stm, &buf); if (tok != PDF_TOK_INT) fz_throw(ctx, "corrupt object stream (%d %d R)", num, gen); - n = atoi(buf); + n = buf.i; if (n >= xref->len) pdf_resize_xref(xref, n + 1); xref->table[n].ofs = num; xref->table[n].gen = i; xref->table[n].stm_ofs = 0; - fz_drop_obj(xref->table[n].obj); + pdf_drop_obj(xref->table[n].obj); xref->table[n].obj = NULL; xref->table[n].type = 'o'; - tok = pdf_lex(stm, buf, sizeof buf, &n); + tok = pdf_lex(stm, &buf); if (tok != PDF_TOK_INT) fz_throw(ctx, "corrupt object stream (%d %d R)", num, gen); } @@ -195,15 +196,15 @@ pdf_repair_obj_stm(pdf_document *xref, int num, int gen) } void -pdf_repair_xref(pdf_document *xref, char *buf, int bufsize) +pdf_repair_xref(pdf_document *xref, pdf_lexbuf *buf) { - fz_obj *dict, *obj; - fz_obj *length; + pdf_obj *dict, *obj; + pdf_obj *length; - fz_obj *encrypt = NULL; - fz_obj *id = NULL; - fz_obj *root = NULL; - fz_obj *info = NULL; + pdf_obj *encrypt = NULL; + pdf_obj *id = NULL; + pdf_obj *root = NULL; + pdf_obj *info = NULL; struct entry *list = NULL; int listlen; @@ -234,14 +235,14 @@ pdf_repair_xref(pdf_document *xref, char *buf, int bufsize) list = fz_malloc_array(ctx, listcap, sizeof(struct entry)); /* look for '%PDF' version marker within first kilobyte of file */ - n = fz_read(xref->file, (unsigned char *)buf, MIN(bufsize, 1024)); + n = fz_read(xref->file, (unsigned char *)buf->scratch, MIN(buf->size, 1024)); if (n < 0) fz_throw(ctx, "cannot read from file"); fz_seek(xref->file, 0, 0); for (i = 0; i < n - 4; i++) { - if (memcmp(buf + i, "%PDF", 4) == 0) + if (memcmp(&buf->scratch[i], "%PDF", 4) == 0) { fz_seek(xref->file, i + 8, 0); /* skip "%PDF-X.Y" */ break; @@ -263,7 +264,7 @@ pdf_repair_xref(pdf_document *xref, char *buf, int bufsize) fz_try(ctx) { - tok = pdf_lex(xref->file, buf, bufsize, &n); + tok = pdf_lex(xref->file, buf); } fz_catch(ctx) { @@ -276,14 +277,14 @@ pdf_repair_xref(pdf_document *xref, char *buf, int bufsize) numofs = genofs; num = gen; genofs = tmpofs; - gen = atoi(buf); + gen = buf->i; } else if (tok == PDF_TOK_OBJ) { fz_try(ctx) { - pdf_repair_obj(xref->file, buf, bufsize, &stm_ofs, &stm_len, &encrypt, &id); + pdf_repair_obj(xref->file, buf, &stm_ofs, &stm_len, &encrypt, &id); } fz_catch(ctx) { @@ -318,7 +319,7 @@ pdf_repair_xref(pdf_document *xref, char *buf, int bufsize) { fz_try(ctx) { - dict = pdf_parse_dict(xref, xref->file, buf, bufsize); + dict = pdf_parse_dict(xref, xref->file, buf); } fz_catch(ctx) { @@ -331,39 +332,39 @@ pdf_repair_xref(pdf_document *xref, char *buf, int bufsize) break; } - obj = fz_dict_gets(dict, "Encrypt"); + obj = pdf_dict_gets(dict, "Encrypt"); if (obj) { if (encrypt) - fz_drop_obj(encrypt); - encrypt = fz_keep_obj(obj); + pdf_drop_obj(encrypt); + encrypt = pdf_keep_obj(obj); } - obj = fz_dict_gets(dict, "ID"); + obj = pdf_dict_gets(dict, "ID"); if (obj) { if (id) - fz_drop_obj(id); - id = fz_keep_obj(obj); + pdf_drop_obj(id); + id = pdf_keep_obj(obj); } - obj = fz_dict_gets(dict, "Root"); + obj = pdf_dict_gets(dict, "Root"); if (obj) { if (root) - fz_drop_obj(root); - root = fz_keep_obj(obj); + pdf_drop_obj(root); + root = pdf_keep_obj(obj); } - obj = fz_dict_gets(dict, "Info"); + obj = pdf_dict_gets(dict, "Info"); if (obj) { if (info) - fz_drop_obj(info); - info = fz_keep_obj(obj); + pdf_drop_obj(info); + info = pdf_keep_obj(obj); } - fz_drop_obj(dict); + pdf_drop_obj(dict); } else if (tok == PDF_TOK_ERROR) @@ -393,11 +394,11 @@ pdf_repair_xref(pdf_document *xref, char *buf, int bufsize) fz_lock(ctx, FZ_LOCK_FILE); /* RJW: "cannot load stream object (%d %d R)", list[i].num, list[i].gen */ - length = fz_new_int(ctx, list[i].stm_len); - fz_dict_puts(dict, "Length", length); - fz_drop_obj(length); + length = pdf_new_int(ctx, list[i].stm_len); + pdf_dict_puts(dict, "Length", length); + pdf_drop_obj(length); - fz_drop_obj(dict); + pdf_drop_obj(dict); } } @@ -422,57 +423,57 @@ pdf_repair_xref(pdf_document *xref, char *buf, int bufsize) /* create a repaired trailer, Root will be added later */ - xref->trailer = fz_new_dict(ctx, 5); + xref->trailer = pdf_new_dict(ctx, 5); - obj = fz_new_int(ctx, maxnum + 1); - fz_dict_puts(xref->trailer, "Size", obj); - fz_drop_obj(obj); + obj = pdf_new_int(ctx, maxnum + 1); + pdf_dict_puts(xref->trailer, "Size", obj); + pdf_drop_obj(obj); if (root) { - fz_dict_puts(xref->trailer, "Root", root); - fz_drop_obj(root); + pdf_dict_puts(xref->trailer, "Root", root); + pdf_drop_obj(root); } if (info) { - fz_dict_puts(xref->trailer, "Info", info); - fz_drop_obj(info); + pdf_dict_puts(xref->trailer, "Info", info); + pdf_drop_obj(info); } if (encrypt) { - if (fz_is_indirect(encrypt)) + if (pdf_is_indirect(encrypt)) { /* create new reference with non-NULL xref pointer */ - obj = fz_new_indirect(ctx, fz_to_num(encrypt), fz_to_gen(encrypt), xref); - fz_drop_obj(encrypt); + obj = pdf_new_indirect(ctx, pdf_to_num(encrypt), pdf_to_gen(encrypt), xref); + pdf_drop_obj(encrypt); encrypt = obj; } - fz_dict_puts(xref->trailer, "Encrypt", encrypt); - fz_drop_obj(encrypt); + pdf_dict_puts(xref->trailer, "Encrypt", encrypt); + pdf_drop_obj(encrypt); } if (id) { - if (fz_is_indirect(id)) + if (pdf_is_indirect(id)) { /* create new reference with non-NULL xref pointer */ - obj = fz_new_indirect(ctx, fz_to_num(id), fz_to_gen(id), xref); - fz_drop_obj(id); + obj = pdf_new_indirect(ctx, pdf_to_num(id), pdf_to_gen(id), xref); + pdf_drop_obj(id); id = obj; } - fz_dict_puts(xref->trailer, "ID", id); - fz_drop_obj(id); + pdf_dict_puts(xref->trailer, "ID", id); + pdf_drop_obj(id); } fz_free(ctx, list); } fz_catch(ctx) { - if (encrypt) fz_drop_obj(encrypt); - if (id) fz_drop_obj(id); - if (root) fz_drop_obj(root); - if (info) fz_drop_obj(info); + if (encrypt) pdf_drop_obj(encrypt); + if (id) pdf_drop_obj(id); + if (root) pdf_drop_obj(root); + if (info) pdf_drop_obj(info); fz_free(ctx, list); fz_rethrow(ctx); } @@ -481,7 +482,7 @@ pdf_repair_xref(pdf_document *xref, char *buf, int bufsize) void pdf_repair_obj_stms(pdf_document *xref) { - fz_obj *dict; + pdf_obj *dict; int i; for (i = 0; i < xref->len; i++) @@ -489,9 +490,9 @@ pdf_repair_obj_stms(pdf_document *xref) if (xref->table[i].stm_ofs) { dict = pdf_load_object(xref, i, 0); - if (!strcmp(fz_to_name(fz_dict_gets(dict, "Type")), "ObjStm")) + if (!strcmp(pdf_to_name(pdf_dict_gets(dict, "Type")), "ObjStm")) pdf_repair_obj_stm(xref, i, 0); - fz_drop_obj(dict); + pdf_drop_obj(dict); } } diff --git a/pdf/pdf_shade.c b/pdf/pdf_shade.c index fb5dd72c..589b7613 100644 --- a/pdf/pdf_shade.c +++ b/pdf/pdf_shade.c @@ -1,5 +1,5 @@ -#include "fitz.h" -#include "mupdf.h" +#include "fitz-internal.h" +#include "mupdf-internal.h" #define HUGENUM 32000 /* how far to extend axial/radial shadings */ #define FUNSEGS 32 /* size of sampled mesh for function-based shadings */ @@ -363,9 +363,9 @@ pdf_sample_shade_function(fz_context *ctx, fz_shade *shade, int funcs, pdf_funct /* Type 1-3 -- Function-based, axial and radial shadings */ static void -pdf_load_function_based_shading(fz_shade *shade, pdf_document *xref, fz_obj *dict, pdf_function *func) +pdf_load_function_based_shading(fz_shade *shade, pdf_document *xref, pdf_obj *dict, pdf_function *func) { - fz_obj *obj; + pdf_obj *obj; float x0, y0, x1, y1; fz_matrix matrix; struct vertex v[4]; @@ -377,18 +377,18 @@ pdf_load_function_based_shading(fz_shade *shade, pdf_document *xref, fz_obj *dic x0 = y0 = 0; x1 = y1 = 1; - obj = fz_dict_gets(dict, "Domain"); - if (fz_array_len(obj) == 4) + obj = pdf_dict_gets(dict, "Domain"); + if (pdf_array_len(obj) == 4) { - x0 = fz_to_real(fz_array_get(obj, 0)); - x1 = fz_to_real(fz_array_get(obj, 1)); - y0 = fz_to_real(fz_array_get(obj, 2)); - y1 = fz_to_real(fz_array_get(obj, 3)); + x0 = pdf_to_real(pdf_array_get(obj, 0)); + x1 = pdf_to_real(pdf_array_get(obj, 1)); + y0 = pdf_to_real(pdf_array_get(obj, 2)); + y1 = pdf_to_real(pdf_array_get(obj, 3)); } matrix = fz_identity; - obj = fz_dict_gets(dict, "Matrix"); - if (fz_array_len(obj) == 6) + obj = pdf_dict_gets(dict, "Matrix"); + if (pdf_array_len(obj) == 6) matrix = pdf_to_matrix(ctx, obj); for (yy = 0; yy < FUNSEGS; yy++) @@ -428,36 +428,36 @@ pdf_load_function_based_shading(fz_shade *shade, pdf_document *xref, fz_obj *dic } static void -pdf_load_axial_shading(fz_shade *shade, pdf_document *xref, fz_obj *dict, int funcs, pdf_function **func) +pdf_load_axial_shading(fz_shade *shade, pdf_document *xref, pdf_obj *dict, int funcs, pdf_function **func) { - fz_obj *obj; + pdf_obj *obj; float d0, d1; int e0, e1; float x0, y0, x1, y1; struct vertex p1, p2; fz_context *ctx = xref->ctx; - obj = fz_dict_gets(dict, "Coords"); - x0 = fz_to_real(fz_array_get(obj, 0)); - y0 = fz_to_real(fz_array_get(obj, 1)); - x1 = fz_to_real(fz_array_get(obj, 2)); - y1 = fz_to_real(fz_array_get(obj, 3)); + obj = pdf_dict_gets(dict, "Coords"); + x0 = pdf_to_real(pdf_array_get(obj, 0)); + y0 = pdf_to_real(pdf_array_get(obj, 1)); + x1 = pdf_to_real(pdf_array_get(obj, 2)); + y1 = pdf_to_real(pdf_array_get(obj, 3)); d0 = 0; d1 = 1; - obj = fz_dict_gets(dict, "Domain"); - if (fz_array_len(obj) == 2) + obj = pdf_dict_gets(dict, "Domain"); + if (pdf_array_len(obj) == 2) { - d0 = fz_to_real(fz_array_get(obj, 0)); - d1 = fz_to_real(fz_array_get(obj, 1)); + d0 = pdf_to_real(pdf_array_get(obj, 0)); + d1 = pdf_to_real(pdf_array_get(obj, 1)); } e0 = e1 = 0; - obj = fz_dict_gets(dict, "Extend"); - if (fz_array_len(obj) == 2) + obj = pdf_dict_gets(dict, "Extend"); + if (pdf_array_len(obj) == 2) { - e0 = fz_to_bool(fz_array_get(obj, 0)); - e1 = fz_to_bool(fz_array_get(obj, 1)); + e0 = pdf_to_bool(pdf_array_get(obj, 0)); + e1 = pdf_to_bool(pdf_array_get(obj, 1)); } pdf_sample_shade_function(ctx, shade, funcs, func, d0, d1); @@ -479,38 +479,38 @@ pdf_load_axial_shading(fz_shade *shade, pdf_document *xref, fz_obj *dict, int fu } static void -pdf_load_radial_shading(fz_shade *shade, pdf_document *xref, fz_obj *dict, int funcs, pdf_function **func) +pdf_load_radial_shading(fz_shade *shade, pdf_document *xref, pdf_obj *dict, int funcs, pdf_function **func) { - fz_obj *obj; + pdf_obj *obj; float d0, d1; int e0, e1; float x0, y0, r0, x1, y1, r1; struct vertex p1, p2; fz_context *ctx = xref->ctx; - obj = fz_dict_gets(dict, "Coords"); - x0 = fz_to_real(fz_array_get(obj, 0)); - y0 = fz_to_real(fz_array_get(obj, 1)); - r0 = fz_to_real(fz_array_get(obj, 2)); - x1 = fz_to_real(fz_array_get(obj, 3)); - y1 = fz_to_real(fz_array_get(obj, 4)); - r1 = fz_to_real(fz_array_get(obj, 5)); + obj = pdf_dict_gets(dict, "Coords"); + x0 = pdf_to_real(pdf_array_get(obj, 0)); + y0 = pdf_to_real(pdf_array_get(obj, 1)); + r0 = pdf_to_real(pdf_array_get(obj, 2)); + x1 = pdf_to_real(pdf_array_get(obj, 3)); + y1 = pdf_to_real(pdf_array_get(obj, 4)); + r1 = pdf_to_real(pdf_array_get(obj, 5)); d0 = 0; d1 = 1; - obj = fz_dict_gets(dict, "Domain"); - if (fz_array_len(obj) == 2) + obj = pdf_dict_gets(dict, "Domain"); + if (pdf_array_len(obj) == 2) { - d0 = fz_to_real(fz_array_get(obj, 0)); - d1 = fz_to_real(fz_array_get(obj, 1)); + d0 = pdf_to_real(pdf_array_get(obj, 0)); + d1 = pdf_to_real(pdf_array_get(obj, 1)); } e0 = e1 = 0; - obj = fz_dict_gets(dict, "Extend"); - if (fz_array_len(obj) == 2) + obj = pdf_dict_gets(dict, "Extend"); + if (pdf_array_len(obj) == 2) { - e0 = fz_to_bool(fz_array_get(obj, 0)); - e1 = fz_to_bool(fz_array_get(obj, 1)); + e0 = pdf_to_bool(pdf_array_get(obj, 0)); + e1 = pdf_to_bool(pdf_array_get(obj, 1)); } pdf_sample_shade_function(ctx, shade, funcs, func, d0, d1); @@ -553,9 +553,9 @@ struct mesh_params }; static void -pdf_load_mesh_params(pdf_document *xref, fz_obj *dict, struct mesh_params *p) +pdf_load_mesh_params(pdf_document *xref, pdf_obj *dict, struct mesh_params *p) { - fz_obj *obj; + pdf_obj *obj; int i, n; p->x0 = p->y0 = 0; @@ -566,23 +566,23 @@ pdf_load_mesh_params(pdf_document *xref, fz_obj *dict, struct mesh_params *p) p->c1[i] = 1; } - p->vprow = fz_to_int(fz_dict_gets(dict, "VerticesPerRow")); - p->bpflag = fz_to_int(fz_dict_gets(dict, "BitsPerFlag")); - p->bpcoord = fz_to_int(fz_dict_gets(dict, "BitsPerCoordinate")); - p->bpcomp = fz_to_int(fz_dict_gets(dict, "BitsPerComponent")); + p->vprow = pdf_to_int(pdf_dict_gets(dict, "VerticesPerRow")); + p->bpflag = pdf_to_int(pdf_dict_gets(dict, "BitsPerFlag")); + p->bpcoord = pdf_to_int(pdf_dict_gets(dict, "BitsPerCoordinate")); + p->bpcomp = pdf_to_int(pdf_dict_gets(dict, "BitsPerComponent")); - obj = fz_dict_gets(dict, "Decode"); - if (fz_array_len(obj) >= 6) + obj = pdf_dict_gets(dict, "Decode"); + if (pdf_array_len(obj) >= 6) { - n = (fz_array_len(obj) - 4) / 2; - p->x0 = fz_to_real(fz_array_get(obj, 0)); - p->x1 = fz_to_real(fz_array_get(obj, 1)); - p->y0 = fz_to_real(fz_array_get(obj, 2)); - p->y1 = fz_to_real(fz_array_get(obj, 3)); + n = (pdf_array_len(obj) - 4) / 2; + p->x0 = pdf_to_real(pdf_array_get(obj, 0)); + p->x1 = pdf_to_real(pdf_array_get(obj, 1)); + p->y0 = pdf_to_real(pdf_array_get(obj, 2)); + p->y1 = pdf_to_real(pdf_array_get(obj, 3)); for (i = 0; i < n; i++) { - p->c0[i] = fz_to_real(fz_array_get(obj, 4 + i * 2)); - p->c1[i] = fz_to_real(fz_array_get(obj, 5 + i * 2)); + p->c0[i] = pdf_to_real(pdf_array_get(obj, 4 + i * 2)); + p->c1[i] = pdf_to_real(pdf_array_get(obj, 5 + i * 2)); } } @@ -603,7 +603,7 @@ pdf_load_mesh_params(pdf_document *xref, fz_obj *dict, struct mesh_params *p) } static void -pdf_load_type4_shade(fz_shade *shade, pdf_document *xref, fz_obj *dict, +pdf_load_type4_shade(fz_shade *shade, pdf_document *xref, pdf_obj *dict, int funcs, pdf_function **func) { fz_context *ctx = xref->ctx; @@ -624,7 +624,7 @@ pdf_load_type4_shade(fz_shade *shade, pdf_document *xref, fz_obj *dict, else ncomp = shade->colorspace->n; - stream = pdf_open_stream(xref, fz_to_num(dict), fz_to_gen(dict)); + stream = pdf_open_stream(xref, pdf_to_num(dict), pdf_to_gen(dict)); while (!fz_is_eof_bits(stream)) { @@ -672,7 +672,7 @@ pdf_load_type4_shade(fz_shade *shade, pdf_document *xref, fz_obj *dict, } static void -pdf_load_type5_shade(fz_shade *shade, pdf_document *xref, fz_obj *dict, +pdf_load_type5_shade(fz_shade *shade, pdf_document *xref, pdf_obj *dict, int funcs, pdf_function **func) { fz_context *ctx = xref->ctx; @@ -697,7 +697,7 @@ pdf_load_type5_shade(fz_shade *shade, pdf_document *xref, fz_obj *dict, buf = fz_malloc_array(ctx, p.vprow, sizeof(struct vertex)); first = 1; - stream = pdf_open_stream(xref, fz_to_num(dict), fz_to_gen(dict)); + stream = pdf_open_stream(xref, pdf_to_num(dict), pdf_to_gen(dict)); while (!fz_is_eof_bits(stream)) { @@ -726,7 +726,7 @@ pdf_load_type5_shade(fz_shade *shade, pdf_document *xref, fz_obj *dict, /* Type 6 & 7 -- Patch mesh shadings */ static void -pdf_load_type6_shade(fz_shade *shade, pdf_document *xref, fz_obj *dict, +pdf_load_type6_shade(fz_shade *shade, pdf_document *xref, pdf_obj *dict, int funcs, pdf_function **func) { fz_context *ctx = xref->ctx; @@ -750,7 +750,7 @@ pdf_load_type6_shade(fz_shade *shade, pdf_document *xref, fz_obj *dict, hasprevpatch = 0; - stream = pdf_open_stream(xref, fz_to_num(dict), fz_to_gen(dict)); + stream = pdf_open_stream(xref, pdf_to_num(dict), pdf_to_gen(dict)); while (!fz_is_eof_bits(stream)) { @@ -849,7 +849,7 @@ pdf_load_type6_shade(fz_shade *shade, pdf_document *xref, fz_obj *dict, } static void -pdf_load_type7_shade(fz_shade *shade, pdf_document *xref, fz_obj *dict, +pdf_load_type7_shade(fz_shade *shade, pdf_document *xref, pdf_obj *dict, int funcs, pdf_function **func) { fz_context *ctx = xref->ctx; @@ -873,7 +873,7 @@ pdf_load_type7_shade(fz_shade *shade, pdf_document *xref, fz_obj *dict, hasprevpatch = 0; - stream = pdf_open_stream(xref, fz_to_num(dict), fz_to_gen(dict)); + stream = pdf_open_stream(xref, pdf_to_num(dict), pdf_to_gen(dict)); while (!fz_is_eof_bits(stream)) { @@ -974,11 +974,11 @@ pdf_load_type7_shade(fz_shade *shade, pdf_document *xref, fz_obj *dict, /* Load all of the shading dictionary parameters, then switch on the shading type. */ static fz_shade * -pdf_load_shading_dict(pdf_document *xref, fz_obj *dict, fz_matrix transform) +pdf_load_shading_dict(pdf_document *xref, pdf_obj *dict, fz_matrix transform) { fz_shade *shade = NULL; pdf_function *func[FZ_MAX_COLORS] = { NULL }; - fz_obj *obj; + pdf_obj *obj; int funcs = 0; int type = 0; int i; @@ -1009,49 +1009,49 @@ pdf_load_shading_dict(pdf_document *xref, fz_obj *dict, fz_matrix transform) funcs = 0; - obj = fz_dict_gets(dict, "ShadingType"); - type = fz_to_int(obj); + obj = pdf_dict_gets(dict, "ShadingType"); + type = pdf_to_int(obj); - obj = fz_dict_gets(dict, "ColorSpace"); + obj = pdf_dict_gets(dict, "ColorSpace"); if (!obj) fz_throw(ctx, "shading colorspace is missing"); shade->colorspace = pdf_load_colorspace(xref, obj); - /* RJW: "cannot load colorspace (%d %d R)", fz_to_num(obj), fz_to_gen(obj) */ + /* RJW: "cannot load colorspace (%d %d R)", pdf_to_num(obj), pdf_to_gen(obj) */ - obj = fz_dict_gets(dict, "Background"); + obj = pdf_dict_gets(dict, "Background"); if (obj) { shade->use_background = 1; for (i = 0; i < shade->colorspace->n; i++) - shade->background[i] = fz_to_real(fz_array_get(obj, i)); + shade->background[i] = pdf_to_real(pdf_array_get(obj, i)); } - obj = fz_dict_gets(dict, "BBox"); - if (fz_is_array(obj)) + obj = pdf_dict_gets(dict, "BBox"); + if (pdf_is_array(obj)) { shade->bbox = pdf_to_rect(ctx, obj); } - obj = fz_dict_gets(dict, "Function"); - if (fz_is_dict(obj)) + obj = pdf_dict_gets(dict, "Function"); + if (pdf_is_dict(obj)) { funcs = 1; func[0] = pdf_load_function(xref, obj); if (!func[0]) - fz_throw(ctx, "cannot load shading function (%d %d R)", fz_to_num(obj), fz_to_gen(obj)); + fz_throw(ctx, "cannot load shading function (%d %d R)", pdf_to_num(obj), pdf_to_gen(obj)); } - else if (fz_is_array(obj)) + else if (pdf_is_array(obj)) { - funcs = fz_array_len(obj); + funcs = pdf_array_len(obj); if (funcs != 1 && funcs != shade->colorspace->n) fz_throw(ctx, "incorrect number of shading functions"); for (i = 0; i < funcs; i++) { - func[i] = pdf_load_function(xref, fz_array_get(obj, i)); + func[i] = pdf_load_function(xref, pdf_array_get(obj, i)); if (!func[i]) - fz_throw(ctx, "cannot load shading function (%d %d R)", fz_to_num(obj), fz_to_gen(obj)); + fz_throw(ctx, "cannot load shading function (%d %d R)", pdf_to_num(obj), pdf_to_gen(obj)); } } @@ -1079,7 +1079,7 @@ pdf_load_shading_dict(pdf_document *xref, fz_obj *dict, fz_matrix transform) pdf_drop_function(ctx, func[i]); fz_drop_shade(ctx, shade); - fz_throw(ctx, "cannot load shading type %d (%d %d R)", type, fz_to_num(dict), fz_to_gen(dict)); + fz_throw(ctx, "cannot load shading type %d (%d %d R)", type, pdf_to_num(dict), pdf_to_gen(dict)); } return shade; } @@ -1093,52 +1093,52 @@ fz_shade_size(fz_shade *s) } fz_shade * -pdf_load_shading(pdf_document *xref, fz_obj *dict) +pdf_load_shading(pdf_document *xref, pdf_obj *dict) { fz_matrix mat; - fz_obj *obj; + pdf_obj *obj; fz_context *ctx = xref->ctx; fz_shade *shade; - if ((shade = fz_find_item(ctx, fz_free_shade_imp, dict))) + if ((shade = pdf_find_item(ctx, fz_free_shade_imp, dict))) { return shade; } /* Type 2 pattern dictionary */ - if (fz_dict_gets(dict, "PatternType")) + if (pdf_dict_gets(dict, "PatternType")) { - obj = fz_dict_gets(dict, "Matrix"); + obj = pdf_dict_gets(dict, "Matrix"); if (obj) mat = pdf_to_matrix(ctx, obj); else mat = fz_identity; - obj = fz_dict_gets(dict, "ExtGState"); + obj = pdf_dict_gets(dict, "ExtGState"); if (obj) { - if (fz_dict_gets(obj, "CA") || fz_dict_gets(obj, "ca")) + if (pdf_dict_gets(obj, "CA") || pdf_dict_gets(obj, "ca")) { fz_warn(ctx, "shading with alpha not supported"); } } - obj = fz_dict_gets(dict, "Shading"); + obj = pdf_dict_gets(dict, "Shading"); if (!obj) fz_throw(ctx, "syntaxerror: missing shading dictionary"); shade = pdf_load_shading_dict(xref, obj, mat); - /* RJW: "cannot load shading dictionary (%d %d R)", fz_to_num(obj), fz_to_gen(obj) */ + /* RJW: "cannot load shading dictionary (%d %d R)", pdf_to_num(obj), pdf_to_gen(obj) */ } /* Naked shading dictionary */ else { shade = pdf_load_shading_dict(xref, dict, fz_identity); - /* RJW: "cannot load shading dictionary (%d %d R)", fz_to_num(dict), fz_to_gen(dict) */ + /* RJW: "cannot load shading dictionary (%d %d R)", pdf_to_num(dict), pdf_to_gen(dict) */ } - fz_store_item(ctx, dict, shade, fz_shade_size(shade)); + pdf_store_item(ctx, dict, shade, fz_shade_size(shade)); return shade; } diff --git a/pdf/pdf_store.c b/pdf/pdf_store.c new file mode 100644 index 00000000..2a3b8b07 --- /dev/null +++ b/pdf/pdf_store.c @@ -0,0 +1,74 @@ +#include "fitz-internal.h" +#include "mupdf-internal.h" + +static int +pdf_make_hash_key(fz_store_hash *hash, void *key_) +{ + pdf_obj *key = (pdf_obj *)key_; + + if (!pdf_is_indirect(key)) + return 0; + hash->u.i.i0 = pdf_to_num(key); + hash->u.i.i1 = pdf_to_gen(key); + return 1; +} + +static void * +pdf_keep_key(fz_context *ctx, void *key) +{ + return (void *)pdf_keep_obj((pdf_obj *)key); +} + +static void +pdf_drop_key(fz_context *ctx, void *key) +{ + pdf_drop_obj((pdf_obj *)key); +} + +static int +pdf_cmp_key(void *k0, void *k1) +{ + return pdf_objcmp((pdf_obj *)k0, (pdf_obj *)k1); +} + +static void +pdf_debug_key(void *key_) +{ + pdf_obj *key = (pdf_obj *)key_; + + if (pdf_is_indirect(key)) + { + printf("(%d %d R) ", pdf_to_num(key), pdf_to_gen(key)); + } else + pdf_print_obj(key); +} + +static fz_store_type pdf_obj_store_type = +{ + pdf_make_hash_key, + pdf_keep_key, + pdf_drop_key, + pdf_cmp_key, + pdf_debug_key +}; + +void +pdf_store_item(fz_context *ctx, pdf_obj *key, void *val, unsigned int itemsize) +{ + void *existing; + existing = fz_store_item(ctx, key, val, itemsize, &pdf_obj_store_type); + assert(existing == NULL); +} + +void * +pdf_find_item(fz_context *ctx, fz_store_free_fn *free, pdf_obj *key) +{ + return fz_find_item(ctx, free, key, &pdf_obj_store_type); +} + +void +pdf_remove_item(fz_context *ctx, fz_store_free_fn *free, pdf_obj *key) +{ + fz_remove_item(ctx, free, key, &pdf_obj_store_type); +} + diff --git a/pdf/pdf_stream.c b/pdf/pdf_stream.c index c66e703e..84f966ec 100644 --- a/pdf/pdf_stream.c +++ b/pdf/pdf_stream.c @@ -1,5 +1,5 @@ -#include "fitz.h" -#include "mupdf.h" +#include "fitz-internal.h" +#include "mupdf-internal.h" /* * Check if an object is a stream or not. @@ -20,24 +20,24 @@ pdf_is_stream(pdf_document *xref, int num, int gen) * Scan stream dictionary for an explicit /Crypt filter */ static int -pdf_stream_has_crypt(fz_context *ctx, fz_obj *stm) +pdf_stream_has_crypt(fz_context *ctx, pdf_obj *stm) { - fz_obj *filters; - fz_obj *obj; + pdf_obj *filters; + pdf_obj *obj; int i; - filters = fz_dict_getsa(stm, "Filter", "F"); + filters = pdf_dict_getsa(stm, "Filter", "F"); if (filters) { - if (!strcmp(fz_to_name(filters), "Crypt")) + if (!strcmp(pdf_to_name(filters), "Crypt")) return 1; - if (fz_is_array(filters)) + if (pdf_is_array(filters)) { - int n = fz_array_len(filters); + int n = pdf_array_len(filters); for (i = 0; i < n; i++) { - obj = fz_array_get(filters, i); - if (!strcmp(fz_to_name(obj), "Crypt")) + obj = pdf_array_get(filters, i); + if (!strcmp(pdf_to_name(obj), "Crypt")) return 1; } } @@ -49,15 +49,15 @@ pdf_stream_has_crypt(fz_context *ctx, fz_obj *stm) * Create a filter given a name and param dictionary. */ static fz_stream * -build_filter(fz_stream *chain, pdf_document * xref, fz_obj * f, fz_obj * p, int num, int gen) +build_filter(fz_stream *chain, pdf_document * xref, pdf_obj * f, pdf_obj * p, int num, int gen, pdf_image_params *params) { fz_context *ctx = chain->ctx; - char *s = fz_to_name(f); + char *s = pdf_to_name(f); - int predictor = fz_to_int(fz_dict_gets(p, "Predictor")); - int columns = fz_to_int(fz_dict_gets(p, "Columns")); - int colors = fz_to_int(fz_dict_gets(p, "Colors")); - int bpc = fz_to_int(fz_dict_gets(p, "BitsPerComponent")); + int predictor = pdf_to_int(pdf_dict_gets(p, "Predictor")); + int columns = pdf_to_int(pdf_dict_gets(p, "Columns")); + int colors = pdf_to_int(pdf_dict_gets(p, "Colors")); + int bpc = pdf_to_int(pdf_dict_gets(p, "BitsPerComponent")); if (predictor == 0) predictor = 1; if (columns == 0) columns = 1; @@ -72,34 +72,71 @@ build_filter(fz_stream *chain, pdf_document * xref, fz_obj * f, fz_obj * p, int else if (!strcmp(s, "CCITTFaxDecode") || !strcmp(s, "CCF")) { - fz_obj *k = fz_dict_gets(p, "K"); - fz_obj *eol = fz_dict_gets(p, "EndOfLine"); - fz_obj *eba = fz_dict_gets(p, "EncodedByteAlign"); - fz_obj *columns = fz_dict_gets(p, "Columns"); - fz_obj *rows = fz_dict_gets(p, "Rows"); - fz_obj *eob = fz_dict_gets(p, "EndOfBlock"); - fz_obj *bi1 = fz_dict_gets(p, "BlackIs1"); + pdf_obj *k = pdf_dict_gets(p, "K"); + pdf_obj *eol = pdf_dict_gets(p, "EndOfLine"); + pdf_obj *eba = pdf_dict_gets(p, "EncodedByteAlign"); + pdf_obj *columns = pdf_dict_gets(p, "Columns"); + pdf_obj *rows = pdf_dict_gets(p, "Rows"); + pdf_obj *eob = pdf_dict_gets(p, "EndOfBlock"); + pdf_obj *bi1 = pdf_dict_gets(p, "BlackIs1"); + if (params) + { + /* We will shortstop here */ + params->type = PDF_IMAGE_FAX; + params->u.fax.k = (k ? pdf_to_int(k) : 0); + params->u.fax.eol = (eol ? pdf_to_bool(eol) : 0); + params->u.fax.eba = (eba ? pdf_to_bool(eba) : 0); + params->u.fax.columns = (columns ? pdf_to_int(columns) : 1728); + params->u.fax.rows = (rows ? pdf_to_int(rows) : 0); + params->u.fax.eob = (eob ? pdf_to_bool(eob) : 1); + params->u.fax.bi1 = (bi1 ? pdf_to_bool(bi1) : 0); + return chain; + } return fz_open_faxd(chain, - k ? fz_to_int(k) : 0, - eol ? fz_to_bool(eol) : 0, - eba ? fz_to_bool(eba) : 0, - columns ? fz_to_int(columns) : 1728, - rows ? fz_to_int(rows) : 0, - eob ? fz_to_bool(eob) : 1, - bi1 ? fz_to_bool(bi1) : 0); + k ? pdf_to_int(k) : 0, + eol ? pdf_to_bool(eol) : 0, + eba ? pdf_to_bool(eba) : 0, + columns ? pdf_to_int(columns) : 1728, + rows ? pdf_to_int(rows) : 0, + eob ? pdf_to_bool(eob) : 1, + bi1 ? pdf_to_bool(bi1) : 0); } else if (!strcmp(s, "DCTDecode") || !strcmp(s, "DCT")) { - fz_obj *ct = fz_dict_gets(p, "ColorTransform"); - return fz_open_dctd(chain, ct ? fz_to_int(ct) : -1); + pdf_obj *ct = pdf_dict_gets(p, "ColorTransform"); + if (params) + { + /* We will shortstop here */ + params->type = PDF_IMAGE_JPEG; + params->u.jpeg.ct = (ct ? pdf_to_int(ct) : -1); + return chain; + } + return fz_open_dctd(chain, ct ? pdf_to_int(ct) : -1); } else if (!strcmp(s, "RunLengthDecode") || !strcmp(s, "RL")) + { + if (params) + { + /* We will shortstop here */ + params->type = PDF_IMAGE_RLD; + return chain; + } return fz_open_rld(chain); - + } else if (!strcmp(s, "FlateDecode") || !strcmp(s, "Fl")) { + if (params) + { + /* We will shortstop here */ + params->type = PDF_IMAGE_FLATE; + params->u.flate.predictor = predictor; + params->u.flate.columns = columns; + params->u.flate.colors = colors; + params->u.flate.bpc = bpc; + return chain; + } chain = fz_open_flated(chain); if (predictor > 1) chain = fz_open_predict(chain, predictor, columns, colors, bpc); @@ -108,8 +145,19 @@ build_filter(fz_stream *chain, pdf_document * xref, fz_obj * f, fz_obj * p, int else if (!strcmp(s, "LZWDecode") || !strcmp(s, "LZW")) { - fz_obj *ec = fz_dict_gets(p, "EarlyChange"); - chain = fz_open_lzwd(chain, ec ? fz_to_int(ec) : 1); + pdf_obj *ec = pdf_dict_gets(p, "EarlyChange"); + if (params) + { + /* We will shortstop here */ + params->type = PDF_IMAGE_LZW; + params->u.lzw.predictor = predictor; + params->u.lzw.columns = columns; + params->u.lzw.colors = colors; + params->u.lzw.bpc = bpc; + params->u.lzw.ec = (ec ? pdf_to_int(ec) : 1); + return chain; + } + chain = fz_open_lzwd(chain, ec ? pdf_to_int(ec) : 1); if (predictor > 1) chain = fz_open_predict(chain, predictor, columns, colors, bpc); return chain; @@ -118,9 +166,9 @@ build_filter(fz_stream *chain, pdf_document * xref, fz_obj * f, fz_obj * p, int else if (!strcmp(s, "JBIG2Decode")) { fz_buffer *globals = NULL; - fz_obj *obj = fz_dict_gets(p, "JBIG2Globals"); + pdf_obj *obj = pdf_dict_gets(p, "JBIG2Globals"); if (obj) - globals = pdf_load_stream(xref, fz_to_num(obj), fz_to_gen(obj)); + globals = pdf_load_stream(xref, pdf_to_num(obj), pdf_to_gen(obj)); /* fz_open_jbig2d takes possession of globals */ return fz_open_jbig2d(chain, globals); } @@ -130,7 +178,7 @@ build_filter(fz_stream *chain, pdf_document * xref, fz_obj * f, fz_obj * p, int else if (!strcmp(s, "Crypt")) { - fz_obj *name; + pdf_obj *name; if (!xref->crypt) { @@ -138,9 +186,9 @@ build_filter(fz_stream *chain, pdf_document * xref, fz_obj * f, fz_obj * p, int return chain; } - name = fz_dict_gets(p, "Name"); - if (fz_is_name(name)) - return pdf_open_crypt_with_filter(chain, xref->crypt, fz_to_name(name), num, gen); + name = pdf_dict_gets(p, "Name"); + if (pdf_is_name(name)) + return pdf_open_crypt_with_filter(chain, xref->crypt, pdf_to_name(name), num, gen); return chain; } @@ -155,18 +203,18 @@ build_filter(fz_stream *chain, pdf_document * xref, fz_obj * f, fz_obj * p, int * Assume ownership of head. */ static fz_stream * -build_filter_chain(fz_stream *chain, pdf_document *xref, fz_obj *fs, fz_obj *ps, int num, int gen) +build_filter_chain(fz_stream *chain, pdf_document *xref, pdf_obj *fs, pdf_obj *ps, int num, int gen, pdf_image_params *params) { - fz_obj *f; - fz_obj *p; + pdf_obj *f; + pdf_obj *p; int i, n; - n = fz_array_len(fs); + n = pdf_array_len(fs); for (i = 0; i < n; i++) { - f = fz_array_get(fs, i); - p = fz_array_get(ps, i); - chain = build_filter(chain, xref, f, p, num, gen); + f = pdf_array_get(fs, i); + p = pdf_array_get(ps, i); + chain = build_filter(chain, xref, f, p, num, gen, (i == n-1 ? params : NULL)); } return chain; @@ -178,7 +226,7 @@ build_filter_chain(fz_stream *chain, pdf_document *xref, fz_obj *fs, fz_obj *ps, * stream length, followed by a decryption filter. */ static fz_stream * -pdf_open_raw_filter(fz_stream *chain, pdf_document *xref, fz_obj *stmobj, int num, int gen) +pdf_open_raw_filter(fz_stream *chain, pdf_document *xref, pdf_obj *stmobj, int num, int gen) { int hascrypt; int len; @@ -187,7 +235,7 @@ pdf_open_raw_filter(fz_stream *chain, pdf_document *xref, fz_obj *stmobj, int nu /* don't close chain when we close this filter */ fz_keep_stream(chain); - len = fz_to_int(fz_dict_gets(stmobj, "Length")); + len = pdf_to_int(pdf_dict_gets(stmobj, "Length")); chain = fz_open_null(chain, len); fz_try(ctx) @@ -210,20 +258,20 @@ pdf_open_raw_filter(fz_stream *chain, pdf_document *xref, fz_obj *stmobj, int nu * to stream length and decrypting. */ static fz_stream * -pdf_open_filter(fz_stream *chain, pdf_document *xref, fz_obj *stmobj, int num, int gen) +pdf_open_filter(fz_stream *chain, pdf_document *xref, pdf_obj *stmobj, int num, int gen, pdf_image_params *imparams) { - fz_obj *filters; - fz_obj *params; + pdf_obj *filters; + pdf_obj *params; - filters = fz_dict_getsa(stmobj, "Filter", "F"); - params = fz_dict_getsa(stmobj, "DecodeParms", "DP"); + filters = pdf_dict_getsa(stmobj, "Filter", "F"); + params = pdf_dict_getsa(stmobj, "DecodeParms", "DP"); chain = pdf_open_raw_filter(chain, xref, stmobj, num, gen); - if (fz_is_name(filters)) - chain = build_filter(chain, xref, filters, params, num, gen); - else if (fz_array_len(filters) > 0) - chain = build_filter_chain(chain, xref, filters, params, num, gen); + if (pdf_is_name(filters)) + chain = build_filter(chain, xref, filters, params, num, gen, imparams); + else if (pdf_array_len(filters) > 0) + chain = build_filter_chain(chain, xref, filters, params, num, gen, imparams); fz_lock_stream(chain); return chain; @@ -234,21 +282,21 @@ pdf_open_filter(fz_stream *chain, pdf_document *xref, fz_obj *stmobj, int num, i * constraining to stream length, and without decryption. */ fz_stream * -pdf_open_inline_stream(pdf_document *xref, fz_obj *stmobj, int length, fz_stream *chain) +pdf_open_inline_stream(pdf_document *xref, pdf_obj *stmobj, int length, fz_stream *chain, pdf_image_params *imparams) { - fz_obj *filters; - fz_obj *params; + pdf_obj *filters; + pdf_obj *params; - filters = fz_dict_getsa(stmobj, "Filter", "F"); - params = fz_dict_getsa(stmobj, "DecodeParms", "DP"); + filters = pdf_dict_getsa(stmobj, "Filter", "F"); + params = pdf_dict_getsa(stmobj, "DecodeParms", "DP"); /* don't close chain when we close this filter */ fz_keep_stream(chain); - if (fz_is_name(filters)) - return build_filter(chain, xref, filters, params, 0, 0); - if (fz_array_len(filters) > 0) - return build_filter_chain(chain, xref, filters, params, 0, 0); + if (pdf_is_name(filters)) + return build_filter(chain, xref, filters, params, 0, 0, imparams); + if (pdf_array_len(filters) > 0) + return build_filter_chain(chain, xref, filters, params, 0, 0, imparams); return fz_open_null(chain, length); } @@ -290,6 +338,12 @@ pdf_open_raw_stream(pdf_document *xref, int num, int gen) fz_stream * pdf_open_stream(pdf_document *xref, int num, int gen) { + return pdf_open_image_stream(xref, num, gen, NULL); +} + +fz_stream * +pdf_open_image_stream(pdf_document *xref, int num, int gen, pdf_image_params *params) +{ pdf_xref_entry *x; fz_stream *stm; @@ -304,20 +358,64 @@ pdf_open_stream(pdf_document *xref, int num, int gen) if (x->stm_ofs == 0) fz_throw(xref->ctx, "object is not a stream"); - stm = pdf_open_filter(xref->file, xref, x->obj, num, gen); + stm = pdf_open_filter(xref->file, xref, x->obj, num, gen, params); fz_seek(xref->file, x->stm_ofs, 0); return stm; } fz_stream * -pdf_open_stream_with_offset(pdf_document *xref, int num, int gen, fz_obj *dict, int stm_ofs) +pdf_open_image_decomp_stream(fz_context *ctx, fz_buffer *buffer, pdf_image_params *params, int *factor) +{ + fz_stream *chain = fz_open_buffer(ctx, buffer); + + switch (params->type) + { + case PDF_IMAGE_FAX: + *factor = 1; + return fz_open_faxd(chain, + params->u.fax.k, + params->u.fax.eol, + params->u.fax.eba, + params->u.fax.columns, + params->u.fax.rows, + params->u.fax.eob, + params->u.fax.bi1); + case PDF_IMAGE_JPEG: + if (*factor > 8) + *factor = 8; + return fz_open_resized_dctd(chain, params->u.jpeg.ct, *factor); + case PDF_IMAGE_RLD: + *factor = 1; + return fz_open_rld(chain); + case PDF_IMAGE_FLATE: + *factor = 1; + chain = fz_open_flated(chain); + if (params->u.flate.predictor > 1) + chain = fz_open_predict(chain, params->u.flate.predictor, params->u.flate.columns, params->u.flate.colors, params->u.flate.bpc); + return chain; + case PDF_IMAGE_LZW: + *factor = 1; + chain = fz_open_lzwd(chain, params->u.lzw.ec); + if (params->u.lzw.predictor > 1) + chain = fz_open_predict(chain, params->u.lzw.predictor, params->u.lzw.columns, params->u.lzw.colors, params->u.lzw.bpc); + return chain; + default: + *factor = 1; + break; + } + + return chain; +} + +fz_stream * +pdf_open_stream_with_offset(pdf_document *xref, int num, int gen, pdf_obj *dict, int stm_ofs) { fz_stream *stm; if (stm_ofs == 0) fz_throw(xref->ctx, "object is not a stream"); - stm = pdf_open_filter(xref->file, xref, dict, num, gen); + stm = pdf_open_filter(xref->file, xref, dict, num, gen, NULL); fz_seek(xref->file, stm_ofs, 0); return stm; } @@ -329,16 +427,16 @@ fz_buffer * pdf_load_raw_stream(pdf_document *xref, int num, int gen) { fz_stream *stm; - fz_obj *dict; + pdf_obj *dict; int len; fz_buffer *buf; dict = pdf_load_object(xref, num, gen); /* RJW: "cannot load stream dictionary (%d %d R)", num, gen */ - len = fz_to_int(fz_dict_gets(dict, "Length")); + len = pdf_to_int(pdf_dict_gets(dict, "Length")); - fz_drop_obj(dict); + pdf_drop_obj(dict); stm = pdf_open_raw_stream(xref, num, gen); /* RJW: "cannot open raw stream (%d %d R)", num, gen */ @@ -372,9 +470,15 @@ pdf_guess_filter_length(int len, char *filter) fz_buffer * pdf_load_stream(pdf_document *xref, int num, int gen) { + return pdf_load_image_stream(xref, num, gen, NULL); +} + +fz_buffer * +pdf_load_image_stream(pdf_document *xref, int num, int gen, pdf_image_params *params) +{ fz_context *ctx = xref->ctx; fz_stream *stm = NULL; - fz_obj *dict, *obj; + pdf_obj *dict, *obj; int i, len, n; fz_buffer *buf; @@ -383,16 +487,16 @@ pdf_load_stream(pdf_document *xref, int num, int gen) dict = pdf_load_object(xref, num, gen); /* RJW: "cannot load stream dictionary (%d %d R)", num, gen */ - len = fz_to_int(fz_dict_gets(dict, "Length")); - obj = fz_dict_gets(dict, "Filter"); - len = pdf_guess_filter_length(len, fz_to_name(obj)); - n = fz_array_len(obj); + len = pdf_to_int(pdf_dict_gets(dict, "Length")); + obj = pdf_dict_gets(dict, "Filter"); + len = pdf_guess_filter_length(len, pdf_to_name(obj)); + n = pdf_array_len(obj); for (i = 0; i < n; i++) - len = pdf_guess_filter_length(len, fz_to_name(fz_array_get(obj, i))); + len = pdf_guess_filter_length(len, pdf_to_name(pdf_array_get(obj, i))); - fz_drop_obj(dict); + pdf_drop_obj(dict); - stm = pdf_open_stream(xref, num, gen); + stm = pdf_open_image_stream(xref, num, gen, params); /* RJW: "cannot open stream (%d %d R)", num, gen */ fz_try(ctx) diff --git a/pdf/pdf_type3.c b/pdf/pdf_type3.c index 777ff756..6603fc8b 100644 --- a/pdf/pdf_type3.c +++ b/pdf/pdf_type3.c @@ -1,22 +1,31 @@ -#include "fitz.h" -#include "mupdf.h" +#include "fitz-internal.h" +#include "mupdf-internal.h" static void -pdf_run_glyph_func(void *doc, fz_obj *rdb, fz_buffer *contents, fz_device *dev, fz_matrix ctm, void *gstate) +pdf_run_glyph_func(void *doc, void *rdb_, fz_buffer *contents, fz_device *dev, fz_matrix ctm, void *gstate) { + pdf_obj *rdb = (pdf_obj *)rdb_; pdf_run_glyph(doc, rdb, contents, dev, ctm, gstate); } +static void +pdf_t3_free_resources(void *doc, void *rdb_) +{ + pdf_obj *rdb = (pdf_obj *)rdb_; + pdf_drop_obj(rdb); +} + + pdf_font_desc * -pdf_load_type3_font(pdf_document *xref, fz_obj *rdb, fz_obj *dict) +pdf_load_type3_font(pdf_document *xref, pdf_obj *rdb, pdf_obj *dict) { char buf[256]; char *estrings[256]; pdf_font_desc *fontdesc = NULL; - fz_obj *encoding; - fz_obj *widths; - fz_obj *charprocs; - fz_obj *obj; + pdf_obj *encoding; + pdf_obj *widths; + pdf_obj *charprocs; + pdf_obj *obj; int first, last; int i, k, n; fz_rect bbox; @@ -27,18 +36,18 @@ pdf_load_type3_font(pdf_document *xref, fz_obj *rdb, fz_obj *dict) fz_try(ctx) { - obj = fz_dict_gets(dict, "Name"); - if (fz_is_name(obj)) - fz_strlcpy(buf, fz_to_name(obj), sizeof buf); + obj = pdf_dict_gets(dict, "Name"); + if (pdf_is_name(obj)) + fz_strlcpy(buf, pdf_to_name(obj), sizeof buf); else sprintf(buf, "Unnamed-T3"); fontdesc = pdf_new_font_desc(ctx); - obj = fz_dict_gets(dict, "FontMatrix"); + obj = pdf_dict_gets(dict, "FontMatrix"); matrix = pdf_to_matrix(ctx, obj); - obj = fz_dict_gets(dict, "FontBBox"); + obj = pdf_dict_gets(dict, "FontBBox"); bbox = pdf_to_rect(ctx, obj); bbox = fz_transform_rect(matrix, bbox); @@ -52,35 +61,35 @@ pdf_load_type3_font(pdf_document *xref, fz_obj *rdb, fz_obj *dict) for (i = 0; i < 256; i++) estrings[i] = NULL; - encoding = fz_dict_gets(dict, "Encoding"); + encoding = pdf_dict_gets(dict, "Encoding"); if (!encoding) { fz_throw(ctx, "syntaxerror: Type3 font missing Encoding"); } - if (fz_is_name(encoding)) - pdf_load_encoding(estrings, fz_to_name(encoding)); + if (pdf_is_name(encoding)) + pdf_load_encoding(estrings, pdf_to_name(encoding)); - if (fz_is_dict(encoding)) + if (pdf_is_dict(encoding)) { - fz_obj *base, *diff, *item; + pdf_obj *base, *diff, *item; - base = fz_dict_gets(encoding, "BaseEncoding"); - if (fz_is_name(base)) - pdf_load_encoding(estrings, fz_to_name(base)); + base = pdf_dict_gets(encoding, "BaseEncoding"); + if (pdf_is_name(base)) + pdf_load_encoding(estrings, pdf_to_name(base)); - diff = fz_dict_gets(encoding, "Differences"); - if (fz_is_array(diff)) + diff = pdf_dict_gets(encoding, "Differences"); + if (pdf_is_array(diff)) { - n = fz_array_len(diff); + n = pdf_array_len(diff); k = 0; for (i = 0; i < n; i++) { - item = fz_array_get(diff, i); - if (fz_is_int(item)) - k = fz_to_int(item); - if (fz_is_name(item)) - estrings[k++] = fz_to_name(item); + item = pdf_array_get(diff, i); + if (pdf_is_int(item)) + k = pdf_to_int(item); + if (pdf_is_name(item)) + estrings[k++] = pdf_to_name(item); if (k < 0) k = 0; if (k > 255) k = 255; } @@ -90,16 +99,16 @@ pdf_load_type3_font(pdf_document *xref, fz_obj *rdb, fz_obj *dict) fontdesc->encoding = pdf_new_identity_cmap(ctx, 0, 1); fontdesc->size += pdf_cmap_size(ctx, fontdesc->encoding); - pdf_load_to_unicode(xref, fontdesc, estrings, NULL, fz_dict_gets(dict, "ToUnicode")); + pdf_load_to_unicode(xref, fontdesc, estrings, NULL, pdf_dict_gets(dict, "ToUnicode")); /* Widths */ pdf_set_default_hmtx(ctx, fontdesc, 0); - first = fz_to_int(fz_dict_gets(dict, "FirstChar")); - last = fz_to_int(fz_dict_gets(dict, "LastChar")); + first = pdf_to_int(pdf_dict_gets(dict, "FirstChar")); + last = pdf_to_int(pdf_dict_gets(dict, "LastChar")); - widths = fz_dict_gets(dict, "Widths"); + widths = pdf_dict_gets(dict, "Widths"); if (!widths) { fz_throw(ctx, "syntaxerror: Type3 font missing Widths"); @@ -107,7 +116,7 @@ pdf_load_type3_font(pdf_document *xref, fz_obj *rdb, fz_obj *dict) for (i = first; i <= last; i++) { - float w = fz_to_real(fz_array_get(widths, i - first)); + float w = pdf_to_real(pdf_array_get(widths, i - first)); w = fontdesc->font->t3matrix.a * w * 1000; fontdesc->font->t3widths[i] = w * 0.001f; pdf_add_hmtx(ctx, fontdesc, i, i, w); @@ -117,11 +126,12 @@ pdf_load_type3_font(pdf_document *xref, fz_obj *rdb, fz_obj *dict) /* Resources -- inherit page resources if the font doesn't have its own */ - fontdesc->font->t3resources = fz_dict_gets(dict, "Resources"); + fontdesc->font->t3freeres = pdf_t3_free_resources; + fontdesc->font->t3resources = pdf_dict_gets(dict, "Resources"); if (!fontdesc->font->t3resources) fontdesc->font->t3resources = rdb; if (fontdesc->font->t3resources) - fz_keep_obj(fontdesc->font->t3resources); + pdf_keep_obj(fontdesc->font->t3resources); if (!fontdesc->font->t3resources) fz_warn(ctx, "no resource dictionary for type 3 font!"); @@ -130,7 +140,7 @@ pdf_load_type3_font(pdf_document *xref, fz_obj *rdb, fz_obj *dict) /* CharProcs */ - charprocs = fz_dict_gets(dict, "CharProcs"); + charprocs = pdf_dict_gets(dict, "CharProcs"); if (!charprocs) { fz_throw(ctx, "syntaxerror: Type3 font missing CharProcs"); @@ -140,10 +150,10 @@ pdf_load_type3_font(pdf_document *xref, fz_obj *rdb, fz_obj *dict) { if (estrings[i]) { - obj = fz_dict_gets(charprocs, estrings[i]); - if (pdf_is_stream(xref, fz_to_num(obj), fz_to_gen(obj))) + obj = pdf_dict_gets(charprocs, estrings[i]); + if (pdf_is_stream(xref, pdf_to_num(obj), pdf_to_gen(obj))) { - fontdesc->font->t3procs[i] = pdf_load_stream(xref, fz_to_num(obj), fz_to_gen(obj)); + fontdesc->font->t3procs[i] = pdf_load_stream(xref, pdf_to_num(obj), pdf_to_gen(obj)); fontdesc->size += fontdesc->font->t3procs[i]->cap; } } @@ -154,7 +164,7 @@ pdf_load_type3_font(pdf_document *xref, fz_obj *rdb, fz_obj *dict) if (fontdesc) fz_drop_font(ctx, fontdesc->font); fz_free(ctx, fontdesc); - fz_throw(ctx, "cannot load type3 font (%d %d R)", fz_to_num(dict), fz_to_gen(dict)); + fz_throw(ctx, "cannot load type3 font (%d %d R)", pdf_to_num(dict), pdf_to_gen(dict)); } return fontdesc; } diff --git a/pdf/pdf_unicode.c b/pdf/pdf_unicode.c index d2534612..c94a6683 100644 --- a/pdf/pdf_unicode.c +++ b/pdf/pdf_unicode.c @@ -1,11 +1,11 @@ -#include "fitz.h" -#include "mupdf.h" +#include "fitz-internal.h" +#include "mupdf-internal.h" /* Load or synthesize ToUnicode map for fonts */ void pdf_load_to_unicode(pdf_document *xref, pdf_font_desc *font, - char **strings, char *collection, fz_obj *cmapstm) + char **strings, char *collection, pdf_obj *cmapstm) { pdf_cmap *cmap; int cid; @@ -14,10 +14,10 @@ pdf_load_to_unicode(pdf_document *xref, pdf_font_desc *font, int i; fz_context *ctx = xref->ctx; - if (pdf_is_stream(xref, fz_to_num(cmapstm), fz_to_gen(cmapstm))) + if (pdf_is_stream(xref, pdf_to_num(cmapstm), pdf_to_gen(cmapstm))) { cmap = pdf_load_embedded_cmap(xref, cmapstm); - /* RJW: "cannot load embedded cmap (%d %d R)", fz_to_num(cmapstm), fz_to_gen(cmapstm) */ + /* RJW: "cannot load embedded cmap (%d %d R)", pdf_to_num(cmapstm), pdf_to_gen(cmapstm) */ font->to_unicode = pdf_new_cmap(ctx); diff --git a/pdf/pdf_xobject.c b/pdf/pdf_xobject.c index 91bf4db3..ffa86184 100644 --- a/pdf/pdf_xobject.c +++ b/pdf/pdf_xobject.c @@ -1,5 +1,5 @@ -#include "fitz.h" -#include "mupdf.h" +#include "fitz-internal.h" +#include "mupdf-internal.h" pdf_xobject * pdf_keep_xobject(fz_context *ctx, pdf_xobject *xobj) @@ -21,10 +21,10 @@ pdf_free_xobject_imp(fz_context *ctx, fz_storable *xobj_) if (xobj->colorspace) fz_drop_colorspace(ctx, xobj->colorspace); if (xobj->resources) - fz_drop_obj(xobj->resources); + pdf_drop_obj(xobj->resources); if (xobj->contents) fz_drop_buffer(ctx, xobj->contents); - fz_drop_obj(xobj->me); + pdf_drop_obj(xobj->me); fz_free(ctx, xobj); } @@ -37,13 +37,13 @@ pdf_xobject_size(pdf_xobject *xobj) } pdf_xobject * -pdf_load_xobject(pdf_document *xref, fz_obj *dict) +pdf_load_xobject(pdf_document *xref, pdf_obj *dict) { pdf_xobject *form; - fz_obj *obj; + pdf_obj *obj; fz_context *ctx = xref->ctx; - if ((form = fz_find_item(ctx, pdf_free_xobject_imp, dict))) + if ((form = pdf_find_item(ctx, pdf_free_xobject_imp, dict))) { return form; } @@ -56,12 +56,12 @@ pdf_load_xobject(pdf_document *xref, fz_obj *dict) form->me = NULL; /* Store item immediately, to avoid possible recursion if objects refer back to this one */ - fz_store_item(ctx, dict, form, pdf_xobject_size(form)); + pdf_store_item(ctx, dict, form, pdf_xobject_size(form)); - obj = fz_dict_gets(dict, "BBox"); + obj = pdf_dict_gets(dict, "BBox"); form->bbox = pdf_to_rect(ctx, obj); - obj = fz_dict_gets(dict, "Matrix"); + obj = pdf_dict_gets(dict, "Matrix"); if (obj) form->matrix = pdf_to_matrix(ctx, obj); else @@ -71,19 +71,19 @@ pdf_load_xobject(pdf_document *xref, fz_obj *dict) form->knockout = 0; form->transparency = 0; - obj = fz_dict_gets(dict, "Group"); + obj = pdf_dict_gets(dict, "Group"); if (obj) { - fz_obj *attrs = obj; + pdf_obj *attrs = obj; - form->isolated = fz_to_bool(fz_dict_gets(attrs, "I")); - form->knockout = fz_to_bool(fz_dict_gets(attrs, "K")); + form->isolated = pdf_to_bool(pdf_dict_gets(attrs, "I")); + form->knockout = pdf_to_bool(pdf_dict_gets(attrs, "K")); - obj = fz_dict_gets(attrs, "S"); - if (fz_is_name(obj) && !strcmp(fz_to_name(obj), "Transparency")) + obj = pdf_dict_gets(attrs, "S"); + if (pdf_is_name(obj) && !strcmp(pdf_to_name(obj), "Transparency")) form->transparency = 1; - obj = fz_dict_gets(attrs, "CS"); + obj = pdf_dict_gets(attrs, "CS"); if (obj) { form->colorspace = pdf_load_colorspace(xref, obj); @@ -92,21 +92,21 @@ pdf_load_xobject(pdf_document *xref, fz_obj *dict) } } - form->resources = fz_dict_gets(dict, "Resources"); + form->resources = pdf_dict_gets(dict, "Resources"); if (form->resources) - fz_keep_obj(form->resources); + pdf_keep_obj(form->resources); fz_try(ctx) { - form->contents = pdf_load_stream(xref, fz_to_num(dict), fz_to_gen(dict)); + form->contents = pdf_load_stream(xref, pdf_to_num(dict), pdf_to_gen(dict)); } fz_catch(ctx) { - fz_remove_item(ctx, pdf_free_xobject_imp, dict); + pdf_remove_item(ctx, pdf_free_xobject_imp, dict); pdf_drop_xobject(ctx, form); - fz_throw(ctx, "cannot load xobject content stream (%d %d R)", fz_to_num(dict), fz_to_gen(dict)); + fz_throw(ctx, "cannot load xobject content stream (%d %d R)", pdf_to_num(dict), pdf_to_gen(dict)); } - form->me = fz_keep_obj(dict); + form->me = pdf_keep_obj(dict); return form; } diff --git a/pdf/pdf_xref.c b/pdf/pdf_xref.c index 7500ded3..e0e9f190 100644 --- a/pdf/pdf_xref.c +++ b/pdf/pdf_xref.c @@ -1,5 +1,5 @@ -#include "fitz.h" -#include "mupdf.h" +#include "fitz-internal.h" +#include "mupdf-internal.h" static inline int iswhite(int ch) { @@ -51,6 +51,7 @@ pdf_read_start_xref(pdf_document *xref) while (iswhite(buf[i]) && i < n) i ++; xref->startxref = atoi((char*)(buf + i)); + return; } } @@ -63,17 +64,16 @@ pdf_read_start_xref(pdf_document *xref) */ static void -pdf_read_old_trailer(pdf_document *xref, char *buf, int cap) +pdf_read_old_trailer(pdf_document *xref, pdf_lexbuf *buf) { int len; char *s; - int n; int t; int tok; int c; - fz_read_line(xref->file, buf, cap); - if (strncmp(buf, "xref", 4) != 0) + fz_read_line(xref->file, buf->scratch, buf->size); + if (strncmp(buf->scratch, "xref", 4) != 0) fz_throw(xref->ctx, "cannot find xref marker"); while (1) @@ -82,8 +82,8 @@ pdf_read_old_trailer(pdf_document *xref, char *buf, int cap) if (!(c >= '0' && c <= '9')) break; - fz_read_line(xref->file, buf, cap); - s = buf; + fz_read_line(xref->file, buf->scratch, buf->size); + s = buf->scratch; fz_strsep(&s, " "); /* ignore ofs */ if (!s) fz_throw(xref->ctx, "invalid range marker in xref"); @@ -102,15 +102,15 @@ pdf_read_old_trailer(pdf_document *xref, char *buf, int cap) fz_try(xref->ctx) { - tok = pdf_lex(xref->file, buf, cap, &n); + tok = pdf_lex(xref->file, buf); if (tok != PDF_TOK_TRAILER) fz_throw(xref->ctx, "expected trailer marker"); - tok = pdf_lex(xref->file, buf, cap, &n); + tok = pdf_lex(xref->file, buf); if (tok != PDF_TOK_OPEN_DICT) fz_throw(xref->ctx, "expected trailer dictionary"); - xref->trailer = pdf_parse_dict(xref, xref->file, buf, cap); + xref->trailer = pdf_parse_dict(xref, xref->file, buf); } fz_catch(xref->ctx) { @@ -119,11 +119,11 @@ pdf_read_old_trailer(pdf_document *xref, char *buf, int cap) } static void -pdf_read_new_trailer(pdf_document *xref, char *buf, int cap) +pdf_read_new_trailer(pdf_document *xref, pdf_lexbuf *buf) { fz_try(xref->ctx) { - xref->trailer = pdf_parse_ind_obj(xref, xref->file, buf, cap, NULL, NULL, NULL); + xref->trailer = pdf_parse_ind_obj(xref, xref->file, buf, NULL, NULL, NULL); } fz_catch(xref->ctx) { @@ -132,7 +132,7 @@ pdf_read_new_trailer(pdf_document *xref, char *buf, int cap) } static void -pdf_read_trailer(pdf_document *xref, char *buf, int cap) +pdf_read_trailer(pdf_document *xref, pdf_lexbuf *buf) { int c; @@ -145,9 +145,9 @@ pdf_read_trailer(pdf_document *xref, char *buf, int cap) { c = fz_peek_byte(xref->file); if (c == 'x') - pdf_read_old_trailer(xref, buf, cap); + pdf_read_old_trailer(xref, buf); else if (c >= '0' && c <= '9') - pdf_read_new_trailer(xref, buf, cap); + pdf_read_new_trailer(xref, buf); else fz_throw(xref->ctx, "cannot recognize xref format: '%c'", c); } @@ -178,8 +178,8 @@ pdf_resize_xref(pdf_document *xref, int newlen) xref->len = newlen; } -static fz_obj * -pdf_read_old_xref(pdf_document *xref, char *buf, int cap) +static pdf_obj * +pdf_read_old_xref(pdf_document *xref, pdf_lexbuf *buf) { int ofs, len; char *s; @@ -187,10 +187,10 @@ pdf_read_old_xref(pdf_document *xref, char *buf, int cap) int tok; int i; int c; - fz_obj *trailer; + pdf_obj *trailer; - fz_read_line(xref->file, buf, cap); - if (strncmp(buf, "xref", 4) != 0) + fz_read_line(xref->file, buf->scratch, buf->size); + if (strncmp(buf->scratch, "xref", 4) != 0) fz_throw(xref->ctx, "cannot find xref marker"); while (1) @@ -199,8 +199,8 @@ pdf_read_old_xref(pdf_document *xref, char *buf, int cap) if (!(c >= '0' && c <= '9')) break; - fz_read_line(xref->file, buf, cap); - s = buf; + fz_read_line(xref->file, buf->scratch, buf->size); + s = buf->scratch; ofs = atoi(fz_strsep(&s, " ")); len = atoi(fz_strsep(&s, " ")); @@ -220,12 +220,12 @@ pdf_read_old_xref(pdf_document *xref, char *buf, int cap) for (i = ofs; i < ofs + len; i++) { - n = fz_read(xref->file, (unsigned char *) buf, 20); + n = fz_read(xref->file, (unsigned char *) buf->scratch, 20); if (n < 0) fz_throw(xref->ctx, "cannot read xref table"); if (!xref->table[i].type) { - s = buf; + s = buf->scratch; /* broken pdfs where line start with white space */ while (*s != '\0' && iswhite(*s)) @@ -242,15 +242,15 @@ pdf_read_old_xref(pdf_document *xref, char *buf, int cap) fz_try(xref->ctx) { - tok = pdf_lex(xref->file, buf, cap, &n); + tok = pdf_lex(xref->file, buf); if (tok != PDF_TOK_TRAILER) fz_throw(xref->ctx, "expected trailer marker"); - tok = pdf_lex(xref->file, buf, cap, &n); + tok = pdf_lex(xref->file, buf); if (tok != PDF_TOK_OPEN_DICT) fz_throw(xref->ctx, "expected trailer dictionary"); - trailer = pdf_parse_dict(xref, xref->file, buf, cap); + trailer = pdf_parse_dict(xref, xref->file, buf); } fz_catch(xref->ctx) { @@ -295,13 +295,13 @@ pdf_read_new_xref_section(pdf_document *xref, fz_stream *stm, int i0, int i1, in /* Entered with file locked. Drops the lock in the middle, but then picks * it up again before exiting. */ -static fz_obj * -pdf_read_new_xref(pdf_document *xref, char *buf, int cap) +static pdf_obj * +pdf_read_new_xref(pdf_document *xref, pdf_lexbuf *buf) { fz_stream *stm = NULL; - fz_obj *trailer = NULL; - fz_obj *index = NULL; - fz_obj *obj = NULL; + pdf_obj *trailer = NULL; + pdf_obj *index = NULL; + pdf_obj *obj = NULL; int num, gen, stm_ofs; int size, w0, w1, w2; int t; @@ -312,7 +312,7 @@ pdf_read_new_xref(pdf_document *xref, char *buf, int cap) fz_try(ctx) { - trailer = pdf_parse_ind_obj(xref, xref->file, buf, cap, &num, &gen, &stm_ofs); + trailer = pdf_parse_ind_obj(xref, xref->file, buf, &num, &gen, &stm_ofs); } fz_catch(ctx) { @@ -322,25 +322,25 @@ pdf_read_new_xref(pdf_document *xref, char *buf, int cap) fz_try(ctx) { fz_unlock(ctx, FZ_LOCK_FILE); - obj = fz_dict_gets(trailer, "Size"); + obj = pdf_dict_gets(trailer, "Size"); if (!obj) fz_throw(ctx, "xref stream missing Size entry (%d %d R)", num, gen); - size = fz_to_int(obj); + size = pdf_to_int(obj); if (size > xref->len) pdf_resize_xref(xref, size); if (num < 0 || num >= xref->len) fz_throw(ctx, "object id (%d %d R) out of range (0..%d)", num, gen, xref->len - 1); - obj = fz_dict_gets(trailer, "W"); + obj = pdf_dict_gets(trailer, "W"); if (!obj) fz_throw(ctx, "xref stream missing W entry (%d %d R)", num, gen); - w0 = fz_to_int(fz_array_get(obj, 0)); - w1 = fz_to_int(fz_array_get(obj, 1)); - w2 = fz_to_int(fz_array_get(obj, 2)); + w0 = pdf_to_int(pdf_array_get(obj, 0)); + w1 = pdf_to_int(pdf_array_get(obj, 1)); + w2 = pdf_to_int(pdf_array_get(obj, 2)); - index = fz_dict_gets(trailer, "Index"); + index = pdf_dict_gets(trailer, "Index"); stm = pdf_open_stream_with_offset(xref, num, gen, trailer, stm_ofs); /* RJW: Ensure pdf_open_stream does fz_throw(ctx, "cannot open compressed xref stream (%d %d R)", num, gen); */ @@ -352,11 +352,11 @@ pdf_read_new_xref(pdf_document *xref, char *buf, int cap) } else { - int n = fz_array_len(index); + int n = pdf_array_len(index); for (t = 0; t < n; t += 2) { - int i0 = fz_to_int(fz_array_get(index, t + 0)); - int i1 = fz_to_int(fz_array_get(index, t + 1)); + int i0 = pdf_to_int(pdf_array_get(index, t + 0)); + int i1 = pdf_to_int(pdf_array_get(index, t + 1)); pdf_read_new_xref_section(xref, stm, i0, i1, w0, w1, w2); } } @@ -367,8 +367,8 @@ pdf_read_new_xref(pdf_document *xref, char *buf, int cap) } fz_catch(ctx) { - fz_drop_obj(trailer); - fz_drop_obj(index); + pdf_drop_obj(trailer); + pdf_drop_obj(index); fz_rethrow(ctx); } fz_lock(ctx, FZ_LOCK_FILE); @@ -377,12 +377,12 @@ pdf_read_new_xref(pdf_document *xref, char *buf, int cap) } /* File is locked on entry, and exit (but may be dropped in the middle) */ -static fz_obj * -pdf_read_xref(pdf_document *xref, int ofs, char *buf, int cap) +static pdf_obj * +pdf_read_xref(pdf_document *xref, int ofs, pdf_lexbuf *buf) { int c; fz_context *ctx = xref->ctx; - fz_obj *trailer; + pdf_obj *trailer; fz_seek(xref->file, ofs, 0); @@ -393,9 +393,9 @@ pdf_read_xref(pdf_document *xref, int ofs, char *buf, int cap) { c = fz_peek_byte(xref->file); if (c == 'x') - trailer = pdf_read_old_xref(xref, buf, cap); + trailer = pdf_read_old_xref(xref, buf); else if (c >= '0' && c <= '9') - trailer = pdf_read_new_xref(xref, buf, cap); + trailer = pdf_read_new_xref(xref, buf); else fz_throw(ctx, "cannot recognize xref format"); } @@ -407,33 +407,33 @@ pdf_read_xref(pdf_document *xref, int ofs, char *buf, int cap) } static void -pdf_read_xref_sections(pdf_document *xref, int ofs, char *buf, int cap) +pdf_read_xref_sections(pdf_document *xref, int ofs, pdf_lexbuf *buf) { - fz_obj *trailer = NULL; - fz_obj *xrefstm = NULL; - fz_obj *prev = NULL; + pdf_obj *trailer = NULL; + pdf_obj *xrefstm = NULL; + pdf_obj *prev = NULL; fz_context *ctx = xref->ctx; fz_try(ctx) { - trailer = pdf_read_xref(xref, ofs, buf, cap); + trailer = pdf_read_xref(xref, ofs, buf); /* FIXME: do we overwrite free entries properly? */ - xrefstm = fz_dict_gets(trailer, "XRefStm"); + xrefstm = pdf_dict_gets(trailer, "XRefStm"); if (xrefstm) - pdf_read_xref_sections(xref, fz_to_int(xrefstm), buf, cap); + pdf_read_xref_sections(xref, pdf_to_int(xrefstm), buf); - prev = fz_dict_gets(trailer, "Prev"); + prev = pdf_dict_gets(trailer, "Prev"); if (prev) - pdf_read_xref_sections(xref, fz_to_int(prev), buf, cap); + pdf_read_xref_sections(xref, pdf_to_int(prev), buf); } fz_catch(ctx) { - fz_drop_obj(trailer); + pdf_drop_obj(trailer); fz_throw(ctx, "cannot read xref at offset %d", ofs); } - fz_drop_obj(trailer); + pdf_drop_obj(trailer); } /* @@ -441,9 +441,9 @@ pdf_read_xref_sections(pdf_document *xref, int ofs, char *buf, int cap) */ static void -pdf_load_xref(pdf_document *xref, char *buf, int bufsize) +pdf_load_xref(pdf_document *xref, pdf_lexbuf *buf) { - fz_obj *size; + pdf_obj *size; int i; fz_context *ctx = xref->ctx; @@ -451,15 +451,15 @@ pdf_load_xref(pdf_document *xref, char *buf, int bufsize) pdf_read_start_xref(xref); - pdf_read_trailer(xref, buf, bufsize); + pdf_read_trailer(xref, buf); - size = fz_dict_gets(xref->trailer, "Size"); + size = pdf_dict_gets(xref->trailer, "Size"); if (!size) fz_throw(ctx, "trailer missing Size entry"); - pdf_resize_xref(xref, fz_to_int(size)); + pdf_resize_xref(xref, pdf_to_int(size)); - pdf_read_xref_sections(xref, xref->startxref, buf, bufsize); + pdf_read_xref_sections(xref, xref->startxref, buf); /* broken pdfs where first object is not free */ if (xref->table[0].type != 'f') @@ -488,10 +488,10 @@ pdf_ocg_set_config(pdf_document *xref, int config) { int i, j, len, len2; pdf_ocg_descriptor *desc = xref->ocg; - fz_obj *obj, *cobj; + pdf_obj *obj, *cobj; char *name; - obj = fz_dict_gets(fz_dict_gets(xref->trailer, "Root"), "OCProperties"); + obj = pdf_dict_gets(pdf_dict_gets(xref->trailer, "Root"), "OCProperties"); if (!obj) { if (config == 0) @@ -501,25 +501,25 @@ pdf_ocg_set_config(pdf_document *xref, int config) } if (config == 0) { - cobj = fz_dict_gets(obj, "D"); + cobj = pdf_dict_gets(obj, "D"); if (!cobj) fz_throw(xref->ctx, "No default OCG config"); } else { - cobj = fz_array_get(fz_dict_gets(obj, "Configs"), config); + cobj = pdf_array_get(pdf_dict_gets(obj, "Configs"), config); if (!cobj) fz_throw(xref->ctx, "Illegal OCG config"); } if (desc->intent) - fz_drop_obj(desc->intent); - desc->intent = fz_dict_gets(cobj, "Intent"); + pdf_drop_obj(desc->intent); + desc->intent = pdf_dict_gets(cobj, "Intent"); if (desc->intent) - fz_keep_obj(desc->intent); + pdf_keep_obj(desc->intent); len = desc->len; - name = fz_to_name(fz_dict_gets(cobj, "BaseState")); + name = pdf_to_name(pdf_dict_gets(cobj, "BaseState")); if (strcmp(name, "Unchanged") == 0) { /* Do nothing */ @@ -539,13 +539,13 @@ pdf_ocg_set_config(pdf_document *xref, int config) } } - obj = fz_dict_gets(cobj, "ON"); - len2 = fz_array_len(obj); + obj = pdf_dict_gets(cobj, "ON"); + len2 = pdf_array_len(obj); for (i = 0; i < len2; i++) { - fz_obj *o = fz_array_get(obj, i); - int n = fz_to_num(o); - int g = fz_to_gen(o); + pdf_obj *o = pdf_array_get(obj, i); + int n = pdf_to_num(o); + int g = pdf_to_gen(o); for (j=0; j < len; j++) { if (desc->ocgs[j].num == n && desc->ocgs[j].gen == g) @@ -556,13 +556,13 @@ pdf_ocg_set_config(pdf_document *xref, int config) } } - obj = fz_dict_gets(cobj, "OFF"); - len2 = fz_array_len(obj); + obj = pdf_dict_gets(cobj, "OFF"); + len2 = pdf_array_len(obj); for (i = 0; i < len2; i++) { - fz_obj *o = fz_array_get(obj, i); - int n = fz_to_num(o); - int g = fz_to_gen(o); + pdf_obj *o = pdf_array_get(obj, i); + int n = pdf_to_num(o); + int g = pdf_to_gen(o); for (j=0; j < len; j++) { if (desc->ocgs[j].num == n && desc->ocgs[j].gen == g) @@ -591,21 +591,21 @@ pdf_ocg_set_config(pdf_document *xref, int config) static void pdf_read_ocg(pdf_document *xref) { - fz_obj *obj, *ocg; + pdf_obj *obj, *ocg; int len, i; pdf_ocg_descriptor *desc; fz_context *ctx = xref->ctx; fz_var(desc); - obj = fz_dict_gets(fz_dict_gets(xref->trailer, "Root"), "OCProperties"); + obj = pdf_dict_gets(pdf_dict_gets(xref->trailer, "Root"), "OCProperties"); if (!obj) return; - ocg = fz_dict_gets(obj, "OCGs"); - if (!ocg || !fz_is_array(ocg)) + ocg = pdf_dict_gets(obj, "OCGs"); + if (!ocg || !pdf_is_array(ocg)) /* Not ever supposed to happen, but live with it. */ return; - len = fz_array_len(ocg); + len = pdf_array_len(ocg); fz_try(ctx) { desc = fz_calloc(ctx, 1, sizeof(*desc)); @@ -614,9 +614,9 @@ pdf_read_ocg(pdf_document *xref) desc->intent = NULL; for (i=0; i < len; i++) { - fz_obj *o = fz_array_get(ocg, i); - desc->ocgs[i].num = fz_to_num(o); - desc->ocgs[i].gen = fz_to_gen(o); + pdf_obj *o = pdf_array_get(ocg, i); + desc->ocgs[i].num = pdf_to_num(o); + desc->ocgs[i].gen = pdf_to_gen(o); desc->ocgs[i].state = 0; } xref->ocg = desc; @@ -639,7 +639,7 @@ pdf_free_ocg(fz_context *ctx, pdf_ocg_descriptor *desc) return; if (desc->intent) - fz_drop_obj(desc->intent); + pdf_drop_obj(desc->intent); fz_free(ctx, desc->ocgs); fz_free(ctx, desc); } @@ -655,10 +655,10 @@ pdf_document * pdf_open_document_with_stream(fz_stream *file) { pdf_document *xref; - fz_obj *encrypt, *id; - fz_obj *dict = NULL; - fz_obj *obj; - fz_obj *nobj = NULL; + pdf_obj *encrypt, *id; + pdf_obj *dict = NULL; + pdf_obj *obj; + pdf_obj *nobj = NULL; int i, repaired = 0; int locked; fz_context *ctx = file->ctx; @@ -667,11 +667,9 @@ pdf_open_document_with_stream(fz_stream *file) fz_var(nobj); fz_var(locked); - /* install pdf specific callback */ - fz_resolve_indirect = pdf_resolve_indirect; - xref = fz_malloc_struct(ctx, pdf_document); pdf_init_document(xref); + xref->lexbuf.base.size = PDF_LEXBUF_LARGE; xref->file = fz_keep_stream(file); xref->ctx = ctx; @@ -681,7 +679,7 @@ pdf_open_document_with_stream(fz_stream *file) fz_try(ctx) { - pdf_load_xref(xref, xref->scratch, sizeof xref->scratch); + pdf_load_xref(xref, &xref->lexbuf.base); } fz_catch(ctx) { @@ -693,7 +691,7 @@ pdf_open_document_with_stream(fz_stream *file) } if (xref->trailer) { - fz_drop_obj(xref->trailer); + pdf_drop_obj(xref->trailer); xref->trailer = NULL; } fz_warn(xref->ctx, "trying to repair broken xref"); @@ -705,14 +703,14 @@ pdf_open_document_with_stream(fz_stream *file) int hasroot, hasinfo; if (repaired) - pdf_repair_xref(xref, xref->scratch, sizeof xref->scratch); + pdf_repair_xref(xref, &xref->lexbuf.base); fz_unlock(ctx, FZ_LOCK_FILE); locked = 0; - encrypt = fz_dict_gets(xref->trailer, "Encrypt"); - id = fz_dict_gets(xref->trailer, "ID"); - if (fz_is_dict(encrypt)) + encrypt = pdf_dict_gets(xref->trailer, "Encrypt"); + id = pdf_dict_gets(xref->trailer, "ID"); + if (pdf_is_dict(encrypt)) xref->crypt = pdf_new_crypt(ctx, encrypt, id); /* Allow lazy clients to read encrypted files with a blank password */ @@ -722,8 +720,8 @@ pdf_open_document_with_stream(fz_stream *file) { pdf_repair_obj_stms(xref); - hasroot = (fz_dict_gets(xref->trailer, "Root") != NULL); - hasinfo = (fz_dict_gets(xref->trailer, "Info") != NULL); + hasroot = (pdf_dict_gets(xref->trailer, "Root") != NULL); + hasinfo = (pdf_dict_gets(xref->trailer, "Info") != NULL); for (i = 1; i < xref->len; i++) { @@ -742,28 +740,28 @@ pdf_open_document_with_stream(fz_stream *file) if (!hasroot) { - obj = fz_dict_gets(dict, "Type"); - if (fz_is_name(obj) && !strcmp(fz_to_name(obj), "Catalog")) + obj = pdf_dict_gets(dict, "Type"); + if (pdf_is_name(obj) && !strcmp(pdf_to_name(obj), "Catalog")) { - nobj = fz_new_indirect(ctx, i, 0, xref); - fz_dict_puts(xref->trailer, "Root", nobj); - fz_drop_obj(nobj); + nobj = pdf_new_indirect(ctx, i, 0, xref); + pdf_dict_puts(xref->trailer, "Root", nobj); + pdf_drop_obj(nobj); nobj = NULL; } } if (!hasinfo) { - if (fz_dict_gets(dict, "Creator") || fz_dict_gets(dict, "Producer")) + if (pdf_dict_gets(dict, "Creator") || pdf_dict_gets(dict, "Producer")) { - nobj = fz_new_indirect(ctx, i, 0, xref); - fz_dict_puts(xref->trailer, "Info", nobj); - fz_drop_obj(nobj); + nobj = pdf_new_indirect(ctx, i, 0, xref); + pdf_dict_puts(xref->trailer, "Info", nobj); + pdf_drop_obj(nobj); nobj = NULL; } } - fz_drop_obj(dict); + pdf_drop_obj(dict); dict = NULL; } } @@ -775,8 +773,8 @@ pdf_open_document_with_stream(fz_stream *file) } fz_catch(ctx) { - fz_drop_obj(dict); - fz_drop_obj(nobj); + pdf_drop_obj(dict); + pdf_drop_obj(nobj); pdf_close_document(xref); fz_throw(ctx, "cannot open document"); } @@ -809,7 +807,7 @@ pdf_close_document(pdf_document *xref) { if (xref->table[i].obj) { - fz_drop_obj(xref->table[i].obj); + pdf_drop_obj(xref->table[i].obj); xref->table[i].obj = NULL; } } @@ -819,21 +817,21 @@ pdf_close_document(pdf_document *xref) if (xref->page_objs) { for (i = 0; i < xref->page_len; i++) - fz_drop_obj(xref->page_objs[i]); + pdf_drop_obj(xref->page_objs[i]); fz_free(ctx, xref->page_objs); } if (xref->page_refs) { for (i = 0; i < xref->page_len; i++) - fz_drop_obj(xref->page_refs[i]); + pdf_drop_obj(xref->page_refs[i]); fz_free(ctx, xref->page_refs); } if (xref->file) fz_close(xref->file); if (xref->trailer) - fz_drop_obj(xref->trailer); + pdf_drop_obj(xref->trailer); if (xref->crypt) pdf_free_crypt(ctx, xref->crypt); @@ -845,7 +843,7 @@ pdf_close_document(pdf_document *xref) } void -pdf_debug_xref(pdf_document *xref) +pdf_print_xref(pdf_document *xref) { int i; printf("xref\n0 %d\n", xref->len); @@ -864,17 +862,17 @@ pdf_debug_xref(pdf_document *xref) */ static void -pdf_load_obj_stm(pdf_document *xref, int num, int gen, char *buf, int cap) +pdf_load_obj_stm(pdf_document *xref, int num, int gen, pdf_lexbuf *buf) { fz_stream *stm = NULL; - fz_obj *objstm = NULL; + pdf_obj *objstm = NULL; int *numbuf = NULL; int *ofsbuf = NULL; - fz_obj *obj; + pdf_obj *obj; int first; int count; - int i, n; + int i; int tok; fz_context *ctx = xref->ctx; @@ -887,8 +885,8 @@ pdf_load_obj_stm(pdf_document *xref, int num, int gen, char *buf, int cap) { objstm = pdf_load_object(xref, num, gen); - count = fz_to_int(fz_dict_gets(objstm, "N")); - first = fz_to_int(fz_dict_gets(objstm, "First")); + count = pdf_to_int(pdf_dict_gets(objstm, "N")); + first = pdf_to_int(pdf_dict_gets(objstm, "First")); numbuf = fz_calloc(ctx, count, sizeof(int)); ofsbuf = fz_calloc(ctx, count, sizeof(int)); @@ -896,15 +894,15 @@ pdf_load_obj_stm(pdf_document *xref, int num, int gen, char *buf, int cap) stm = pdf_open_stream(xref, num, gen); for (i = 0; i < count; i++) { - tok = pdf_lex(stm, buf, cap, &n); + tok = pdf_lex(stm, buf); if (tok != PDF_TOK_INT) fz_throw(ctx, "corrupt object stream (%d %d R)", num, gen); - numbuf[i] = atoi(buf); + numbuf[i] = buf->i; - tok = pdf_lex(stm, buf, cap, &n); + tok = pdf_lex(stm, buf); if (tok != PDF_TOK_INT) fz_throw(ctx, "corrupt object stream (%d %d R)", num, gen); - ofsbuf[i] = atoi(buf); + ofsbuf[i] = buf->i; } fz_seek(stm, first, 0); @@ -913,24 +911,24 @@ pdf_load_obj_stm(pdf_document *xref, int num, int gen, char *buf, int cap) { fz_seek(stm, first + ofsbuf[i], 0); - obj = pdf_parse_stm_obj(xref, stm, buf, cap); + obj = pdf_parse_stm_obj(xref, stm, buf); /* RJW: Ensure above does fz_throw(ctx, "cannot parse object %d in stream (%d %d R)", i, num, gen); */ if (numbuf[i] < 1 || numbuf[i] >= xref->len) { - fz_drop_obj(obj); + pdf_drop_obj(obj); fz_throw(ctx, "object id (%d 0 R) out of range (0..%d)", numbuf[i], xref->len - 1); } if (xref->table[numbuf[i]].type == 'o' && xref->table[numbuf[i]].ofs == num) { if (xref->table[numbuf[i]].obj) - fz_drop_obj(xref->table[numbuf[i]].obj); + pdf_drop_obj(xref->table[numbuf[i]].obj); xref->table[numbuf[i]].obj = obj; } else { - fz_drop_obj(obj); + pdf_drop_obj(obj); } } } @@ -939,7 +937,7 @@ pdf_load_obj_stm(pdf_document *xref, int num, int gen, char *buf, int cap) fz_close(stm); fz_free(xref->ctx, ofsbuf); fz_free(xref->ctx, numbuf); - fz_drop_obj(objstm); + pdf_drop_obj(objstm); } fz_catch(ctx) { @@ -968,7 +966,7 @@ pdf_cache_object(pdf_document *xref, int num, int gen) if (x->type == 'f') { - x->obj = fz_new_null(ctx); + x->obj = pdf_new_null(ctx); return; } else if (x->type == 'n') @@ -978,7 +976,7 @@ pdf_cache_object(pdf_document *xref, int num, int gen) fz_try(ctx) { - x->obj = pdf_parse_ind_obj(xref, xref->file, xref->scratch, sizeof xref->scratch, + x->obj = pdf_parse_ind_obj(xref, xref->file, &xref->lexbuf.base, &rnum, &rgen, &x->stm_ofs); } fz_catch(ctx) @@ -989,7 +987,7 @@ pdf_cache_object(pdf_document *xref, int num, int gen) if (rnum != num) { - fz_drop_obj(x->obj); + pdf_drop_obj(x->obj); x->obj = NULL; fz_unlock(ctx, FZ_LOCK_FILE); fz_throw(ctx, "found object (%d %d R) instead of (%d %d R)", rnum, rgen, num, gen); @@ -1005,7 +1003,7 @@ pdf_cache_object(pdf_document *xref, int num, int gen) { fz_try(ctx) { - pdf_load_obj_stm(xref, x->ofs, 0, xref->scratch, sizeof xref->scratch); + pdf_load_obj_stm(xref, x->ofs, 0, &xref->lexbuf.base); } fz_catch(ctx) { @@ -1021,7 +1019,7 @@ pdf_cache_object(pdf_document *xref, int num, int gen) } } -fz_obj * +pdf_obj * pdf_load_object(pdf_document *xref, int num, int gen) { fz_context *ctx = xref->ctx; @@ -1037,11 +1035,11 @@ pdf_load_object(pdf_document *xref, int num, int gen) assert(xref->table[num].obj); - return fz_keep_obj(xref->table[num].obj); + return pdf_keep_obj(xref->table[num].obj); } -fz_obj * -pdf_resolve_indirect(fz_obj *ref) +pdf_obj * +pdf_resolve_indirect(pdf_obj *ref) { int sanity = 10; int num; @@ -1049,16 +1047,16 @@ pdf_resolve_indirect(fz_obj *ref) fz_context *ctx = NULL; /* Avoid warning for stupid compilers */ pdf_document *xref; - while (fz_is_indirect(ref)) + while (pdf_is_indirect(ref)) { if (--sanity == 0) fz_throw(ctx, "Too many indirections (possible indirection cycle involving %d %d R)", num, gen); - xref = fz_get_indirect_document(ref); + xref = pdf_get_indirect_document(ref); if (!xref) return NULL; ctx = xref->ctx; - num = fz_to_num(ref); - gen = fz_to_gen(ref); + num = pdf_to_num(ref); + gen = pdf_to_gen(ref); fz_try(ctx) { pdf_cache_object(xref, num, gen); @@ -1076,9 +1074,14 @@ pdf_resolve_indirect(fz_obj *ref) return ref; } +int pdf_count_objects(pdf_document *doc) +{ + return doc->len; +} + /* Replace numbered object -- for use by pdfclean and similar tools */ void -pdf_update_object(pdf_document *xref, int num, int gen, fz_obj *newobj) +pdf_update_object(pdf_document *xref, int num, int gen, pdf_obj *newobj) { pdf_xref_entry *x; @@ -1091,9 +1094,9 @@ pdf_update_object(pdf_document *xref, int num, int gen, fz_obj *newobj) x = &xref->table[num]; if (x->obj) - fz_drop_obj(x->obj); + pdf_drop_obj(x->obj); - x->obj = fz_keep_obj(newobj); + x->obj = pdf_keep_obj(newobj); x->type = 'n'; x->ofs = 0; } diff --git a/scripts/cmapdump.c b/scripts/cmapdump.c index 12d6f2af..53247339 100644 --- a/scripts/cmapdump.c +++ b/scripts/cmapdump.c @@ -6,8 +6,8 @@ /* We never want to build memento versions of the cmapdump util */ #undef MEMENTO -#include "fitz.h" -#include "mupdf.h" +#include "fitz-internal.h" +#include "mupdf-internal.h" #include "../fitz/base_context.c" #include "../fitz/base_error.c" @@ -181,6 +181,10 @@ void fz_free_aa_context(fz_context *ctx) { } +void fz_copy_aa_context(fz_context *dst, fz_context *src) +{ +} + void *fz_keep_storable(fz_context *ctx, fz_storable *s) { return s; @@ -198,7 +202,7 @@ void fz_drop_store_context(fz_context *ctx) { } -fz_store *fz_store_keep(fz_context *ctx) +fz_store *fz_keep_store_context(fz_context *ctx) { return NULL; } diff --git a/scripts/rename2.sed b/scripts/rename2.sed new file mode 100644 index 00000000..152d9613 --- /dev/null +++ b/scripts/rename2.sed @@ -0,0 +1,75 @@ +s/fz_obj/pdf_obj/g +s/pdf_resolve_indirect/pdf_resolve_indirect_imp/g +s/fz_resolve_indirect/pdf_resolve_indirect/g +s/fz_new_null/pdf_new_null/g +s/fz_new_bool/pdf_new_bool/g +s/fz_new_int/pdf_new_int/g +s/fz_new_real/pdf_new_real/g +s/fz_new_string/pdf_new_string/g +s/fz_new_indirect/pdf_new_indirect/g +s/fz_new_array/pdf_new_array/g +s/fz_new_dict/pdf_new_dict/g +s/fz_copy_array/pdf_copy_array/g +s/fz_copy_dict/pdf_copy_dict/g +s/fz_keep_obj/pdf_keep_obj/g +s/fz_drop_obj/pdf_drop_obj/g +s/fz_is_null/pdf_is_null/g +s/fz_is_bool/pdf_is_bool/g +s/fz_is_int/pdf_is_int/g +s/fz_is_real/pdf_is_real/g +s/fz_is_name/pdf_is_name/g +s/fz_is_string/pdf_is_string/g +s/fz_is_array/pdf_is_array/g +s/fz_is_dict/pdf_is_dict/g +s/fz_is_indirect/pdf_is_indirect/g +s/fz_objcmp/pdf_objcmp/g +s/fz_dict_marked/pdf_dict_marked/g +s/fz_dict_mark/pdf_dict_mark/g +s/fz_dict_unmark/pdf_dict_unmark/g +s/fz_to_bool/pdf_to_bool/g +s/fz_to_int/pdf_to_int/g +s/fz_to_real/pdf_to_real/g +s/fz_to_name/pdf_to_name/g +s/fz_to_str_buf/pdf_to_str_buf/g +s/fz_to_dict/pdf_to_dict/g +s/fz_to_str_len/pdf_to_str_len/g +s/fz_to_num/pdf_to_num/g +s/fz_to_gen/pdf_to_gen/g +s/fz_array_len/pdf_array_len/g +s/fz_array_get/pdf_array_get/g +s/fz_array_put/pdf_array_put/g +s/fz_array_push/pdf_array_push/g +s/fz_array_insert/pdf_array_insert/g +s/fz_array_contains/pdf_array_contains/g +s/fz_dict_len/pdf_dict_len/g +s/fz_dict_get_val/pdf_dict_get_val/g +s/fz_dict_get_key/pdf_dict_get_key/g +s/fz_dict_get/pdf_dict_get/g +s/fz_dict_gets/pdf_dict_gets/g +s/fz_dict_getsa/pdf_dict_getsa/g +s/fz_dict_put/fz_dict_put/g +s/fz_dict_puts/pdf_dict_puts/g +s/fz_dict_del/pdf_dict_del/g +s/fz_dict_dels/pdf_dict_dels/g +s/fz_sort_dict/pdf_sort_dict/g +s/fz_fprint_obj/pdf_fprint_obj/g +s/fz_debug_obj/pdf_debug_obj/g +s/fz_debug_ref/pdf_debug_ref/g +s/fz_set_str_len/pdf_set_str_len/g +s/fz_get_indirect_document/pdf_get_indirect_document/g +s/FZ_NULL/PDF_NULL/g +s/FZ_BOOL/PDF_BOOL/g +s/FZ_INT/PDF_INT/g +s/FZ_REAL/PDF_REAL/g +s/FZ_STRING/PDF_STRING/g +s/FZ_NAME/PDF_NAME/g +s/FZ_ARRAY/PDF_ARRAY/g +s/FZ_DICT/PDF_DICT/g +s/FZ_INDIRECT/PDF_INDIRECT/g +s/fz_objkindstr/pdf_objkindstr/g +s/fz_array_grow/pdf_array_grow/g +s/fz_dict_grow/pdf_dict_grow/g +s/fz_dict_finds/pdf_dict_finds/g +s/fz_free_array/pdf_free_array/g +s/fz_free_dict/pdf_free_dict/g +s/fz_sprint_obj/pdf_sprint_obj/g diff --git a/scripts/rename3.sed b/scripts/rename3.sed new file mode 100644 index 00000000..41868e01 --- /dev/null +++ b/scripts/rename3.sed @@ -0,0 +1,37 @@ +s/\<fz_save_pixmap\>/fz_write_pixmap/g +s/\<fz_debug_hash\>/fz_print_hash/g +s/\<fz_debug_store\>/fz_print_store/g +s/\<fz_debug_font\>/fz_print_font/g +s/\<fz_debug_path\>/fz_print_path/g +s/\<fz_debug_text\>/fz_print_text/g +s/\<fz_debug_shade\>/fz_print_shade/g +s/\<fz_debug_outline_xml\>/fz_print_outline_xml/g +s/\<fz_debug_outline\>/fz_print_outline/g +s/\<pdf_debug_xref\>/pdf_print_xref/g +s/\<pdf_debug_crypt\>/pdf_print_crypt/g +s/\<pdf_debug_cmap\>/pdf_print_cmap/g +s/\<pdf_debug_font\>/pdf_print_font/g +s/\<pdf_debug_obj\>/pdf_print_obj/g +s/\<pdf_debug_ref\>/pdf_print_ref/g +s/\<xps_debug_page_list\>/xps_print_page_list/g +s/\<xps_debug_path\>/xps_print_path/g +s/\<xps_debug_resource_dictionary\>/xps_print_resource_dictionary/g +s/\<fz_get_default_halftone\>/fz_default_halftone/g +s/\<fz_get_aa_level\>/fz_aa_level/g +s/\<fz_pixmap_pixels\>/fz_pixmap_samples/g +s/\<pdf_get_crypt_revision\>/pdf_crypt_revision/g +s/\<pdf_get_crypt_method\>/pdf_crypt_method/g +s/\<pdf_get_crypt_length\>/pdf_crypt_length/g +s/\<pdf_get_crypt_key\>/pdf_crypt_key/g +s/\<pdf_set_wmode\>/pdf_set_cmap_wmode/g +s/\<pdf_get_wmode\>/pdf_cmap_wmode/g +s/\<pdf_get_hmtx\>/pdf_lookup_hmtx/g +s/\<pdf_get_vmtx\>/pdf_lookup_vmtx/g +s/\<fz_find_blendmode\>/fz_lookup_blendmode/g +s/\<pdf_find_page_number\>/pdf_lookup_page_number/g +s/\<xps_find_link_target\>/xps_lookup_link_target/g +s/\<pdf_find_builtin_font\>/pdf_lookup_builtin_font/g +s/\<pdf_find_substitute_font\>/pdf_lookup_substitute_font/g +s/\<pdf_find_substitute_cjk_font\>/pdf_lookup_substitute_cjk_font/g +s/\<fz_new_pixmap_with_rect_and_data\>/fz_new_pixmap_with_bbox_and_data/g +s/\<fz_new_pixmap_with_rect\>/fz_new_pixmap_with_bbox/g diff --git a/win32/libmupdf.vcproj b/win32/libmupdf.vcproj index 9a8bb6e9..543cac48 100644 --- a/win32/libmupdf.vcproj +++ b/win32/libmupdf.vcproj @@ -41,7 +41,7 @@ <Tool Name="VCCLCompilerTool" Optimization="0" - AdditionalIncludeDirectories="..\scripts;..\fitz;..\pdf;..\thirdparty\jbig2dec;..\thirdparty\jpeg-8d;..\thirdparty\openjpeg-1.4\libopenjpeg;..\thirdparty\zlib-1.2.5;..\thirdparty\freetype-2.4.8\include" + AdditionalIncludeDirectories="..\scripts;..\fitz;..\pdf;..\thirdparty\jbig2dec;..\thirdparty\jpeg-8d;..\thirdparty\openjpeg-1.5.0\libopenjpeg;..\thirdparty\zlib-1.2.5;..\thirdparty\freetype-2.4.8\include" PreprocessorDefinitions="DEBUG=1" MinimalRebuild="true" BasicRuntimeChecks="3" @@ -106,7 +106,7 @@ Name="VCCLCompilerTool" Optimization="2" EnableIntrinsicFunctions="true" - AdditionalIncludeDirectories="..\scripts;..\fitz;..\pdf;..\thirdparty\jbig2dec;..\thirdparty\jpeg-8d;..\thirdparty\openjpeg-1.4\libopenjpeg;..\thirdparty\zlib-1.2.5;..\thirdparty\freetype-2.4.8\include" + AdditionalIncludeDirectories="..\scripts;..\fitz;..\pdf;..\thirdparty\jbig2dec;..\thirdparty\jpeg-8d;..\thirdparty\openjpeg-1.5.0\libopenjpeg;..\thirdparty\zlib-1.2.5;..\thirdparty\freetype-2.4.8\include" RuntimeLibrary="0" EnableFunctionLevelLinking="true" WarningLevel="3" @@ -166,7 +166,7 @@ <Tool Name="VCCLCompilerTool" Optimization="0" - AdditionalIncludeDirectories="..\scripts;..\fitz;..\pdf;..\thirdparty\jbig2dec;..\thirdparty\jpeg-8d;..\thirdparty\openjpeg-1.4\libopenjpeg;..\thirdparty\zlib-1.2.5;..\thirdparty\freetype-2.4.8\include" + AdditionalIncludeDirectories="..\scripts;..\fitz;..\pdf;..\thirdparty\jbig2dec;..\thirdparty\jpeg-8d;..\thirdparty\openjpeg-1.5.0\libopenjpeg;..\thirdparty\zlib-1.2.5;..\thirdparty\freetype-2.4.8\include" PreprocessorDefinitions="MEMENTO=1;DEBUG=1" MinimalRebuild="true" BasicRuntimeChecks="3" @@ -210,6 +210,10 @@ Name="pdf" > <File + RelativePath="..\pdf\base_object.c" + > + </File> + <File RelativePath="..\pdf\data_encodings.h" > </File> @@ -218,6 +222,10 @@ > </File> <File + RelativePath="..\pdf\mupdf-internal.h" + > + </File> + <File RelativePath="..\pdf\mupdf.h" > </File> @@ -310,6 +318,10 @@ > </File> <File + RelativePath="..\pdf\pdf_store.c" + > + </File> + <File RelativePath="..\pdf\pdf_stream.c" > </File> @@ -358,10 +370,6 @@ > </File> <File - RelativePath="..\fitz\base_object.c" - > - </File> - <File RelativePath="..\fitz\base_string.c" > </File> @@ -446,6 +454,10 @@ > </File> <File + RelativePath="..\fitz\fitz-internal.h" + > + </File> + <File RelativePath="..\fitz\fitz.h" > </File> @@ -458,10 +470,18 @@ > </File> <File + RelativePath="..\fitz\image_md5.c" + > + </File> + <File RelativePath="..\fitz\image_png.c" > </File> <File + RelativePath="..\fitz\image_save.c" + > + </File> + <File RelativePath="..\fitz\image_tiff.c" > </File> diff --git a/win32/libthirdparty.vcproj b/win32/libthirdparty.vcproj index 18c08942..e5419564 100644 --- a/win32/libthirdparty.vcproj +++ b/win32/libthirdparty.vcproj @@ -39,7 +39,7 @@ <Tool Name="VCCLCompilerTool" Optimization="0" - AdditionalIncludeDirectories="..\scripts;..\thirdparty\jbig2dec;..\thirdparty\jpeg-8d;..\thirdparty\openjpeg-1.4\libopenjpeg;..\thirdparty\zlib-1.2.5;..\thirdparty\freetype-2.4.8\include" + AdditionalIncludeDirectories="..\scripts;..\thirdparty\jbig2dec;..\thirdparty\jpeg-8d;..\thirdparty\openjpeg-1.5.0\libopenjpeg;..\thirdparty\zlib-1.2.5;..\thirdparty\freetype-2.4.8\include" PreprocessorDefinitions="_CRT_SECURE_NO_WARNINGS;FT2_BUILD_LIBRARY;OPJ_STATIC;FT_CONFIG_MODULES_H=\"slimftmodules.h\";FT_CONFIG_OPTIONS_H=\"slimftoptions.h\";DEBUG=1" MinimalRebuild="true" BasicRuntimeChecks="3" @@ -102,7 +102,7 @@ Name="VCCLCompilerTool" Optimization="2" EnableIntrinsicFunctions="true" - AdditionalIncludeDirectories="..\scripts;..\thirdparty\jbig2dec;..\thirdparty\jpeg-8d;..\thirdparty\openjpeg-1.4\libopenjpeg;..\thirdparty\zlib-1.2.5;..\thirdparty\freetype-2.4.8\include" + AdditionalIncludeDirectories="..\scripts;..\thirdparty\jbig2dec;..\thirdparty\jpeg-8d;..\thirdparty\openjpeg-1.5.0\libopenjpeg;..\thirdparty\zlib-1.2.5;..\thirdparty\freetype-2.4.8\include" PreprocessorDefinitions="_CRT_SECURE_NO_WARNINGS;FT2_BUILD_LIBRARY;OPJ_STATIC;FT_CONFIG_MODULES_H=\"slimftmodules.h\";FT_CONFIG_OPTIONS_H=\"slimftoptions.h\"" RuntimeLibrary="0" EnableFunctionLevelLinking="true" @@ -162,7 +162,7 @@ <Tool Name="VCCLCompilerTool" Optimization="0" - AdditionalIncludeDirectories="..\scripts;..\thirdparty\jbig2dec;..\thirdparty\jpeg-8d;..\thirdparty\openjpeg-1.4\libopenjpeg;..\thirdparty\zlib-1.2.5;..\thirdparty\freetype-2.4.8\include" + AdditionalIncludeDirectories="..\scripts;..\thirdparty\jbig2dec;..\thirdparty\jpeg-8d;..\thirdparty\openjpeg-1.5.0\libopenjpeg;..\thirdparty\zlib-1.2.5;..\thirdparty\freetype-2.4.8\include" PreprocessorDefinitions="_CRT_SECURE_NO_WARNINGS;FT2_BUILD_LIBRARY;OPJ_STATIC;FT_CONFIG_MODULES_H=\"slimftmodules.h\";FT_CONFIG_OPTIONS_H=\"slimftoptions.h\";MEMENTO=1;DEBUG=1" MinimalRebuild="true" BasicRuntimeChecks="3" @@ -442,75 +442,95 @@ Name="libopenjpeg" > <File - RelativePath="..\thirdparty\openjpeg-1.4\libopenjpeg\bio.c" + RelativePath="..\thirdparty\openjpeg-1.5.0\libopenjpeg\bio.c" > </File> <File - RelativePath="..\thirdparty\openjpeg-1.4\libopenjpeg\cio.c" + RelativePath="..\thirdparty\openjpeg-1.5.0\libopenjpeg\cidx_manager.c" > </File> <File - RelativePath="..\thirdparty\openjpeg-1.4\libopenjpeg\dwt.c" + RelativePath="..\thirdparty\openjpeg-1.5.0\libopenjpeg\cio.c" > </File> <File - RelativePath="..\thirdparty\openjpeg-1.4\libopenjpeg\event.c" + RelativePath="..\thirdparty\openjpeg-1.5.0\libopenjpeg\dwt.c" > </File> <File - RelativePath="..\thirdparty\openjpeg-1.4\libopenjpeg\image.c" + RelativePath="..\thirdparty\openjpeg-1.5.0\libopenjpeg\event.c" > </File> <File - RelativePath="..\thirdparty\openjpeg-1.4\libopenjpeg\j2k.c" + RelativePath="..\thirdparty\openjpeg-1.5.0\libopenjpeg\image.c" > </File> <File - RelativePath="..\thirdparty\openjpeg-1.4\libopenjpeg\j2k_lib.c" + RelativePath="..\thirdparty\openjpeg-1.5.0\libopenjpeg\j2k.c" > </File> <File - RelativePath="..\thirdparty\openjpeg-1.4\libopenjpeg\jp2.c" + RelativePath="..\thirdparty\openjpeg-1.5.0\libopenjpeg\j2k_lib.c" > </File> <File - RelativePath="..\thirdparty\openjpeg-1.4\libopenjpeg\jpt.c" + RelativePath="..\thirdparty\openjpeg-1.5.0\libopenjpeg\jp2.c" > </File> <File - RelativePath="..\thirdparty\openjpeg-1.4\libopenjpeg\mct.c" + RelativePath="..\thirdparty\openjpeg-1.5.0\libopenjpeg\jpt.c" > </File> <File - RelativePath="..\thirdparty\openjpeg-1.4\libopenjpeg\mqc.c" + RelativePath="..\thirdparty\openjpeg-1.5.0\libopenjpeg\mct.c" > </File> <File - RelativePath="..\thirdparty\openjpeg-1.4\libopenjpeg\openjpeg.c" + RelativePath="..\thirdparty\openjpeg-1.5.0\libopenjpeg\mqc.c" > </File> <File - RelativePath="..\thirdparty\openjpeg-1.4\libopenjpeg\pi.c" + RelativePath="..\thirdparty\openjpeg-1.5.0\libopenjpeg\openjpeg.c" > </File> <File - RelativePath="..\thirdparty\openjpeg-1.4\libopenjpeg\raw.c" + RelativePath="..\thirdparty\openjpeg-1.5.0\libopenjpeg\phix_manager.c" > </File> <File - RelativePath="..\thirdparty\openjpeg-1.4\libopenjpeg\t1.c" + RelativePath="..\thirdparty\openjpeg-1.5.0\libopenjpeg\pi.c" > </File> <File - RelativePath="..\thirdparty\openjpeg-1.4\libopenjpeg\t2.c" + RelativePath="..\thirdparty\openjpeg-1.5.0\libopenjpeg\ppix_manager.c" > </File> <File - RelativePath="..\thirdparty\openjpeg-1.4\libopenjpeg\tcd.c" + RelativePath="..\thirdparty\openjpeg-1.5.0\libopenjpeg\raw.c" > </File> <File - RelativePath="..\thirdparty\openjpeg-1.4\libopenjpeg\tgt.c" + RelativePath="..\thirdparty\openjpeg-1.5.0\libopenjpeg\t1.c" + > + </File> + <File + RelativePath="..\thirdparty\openjpeg-1.5.0\libopenjpeg\t2.c" + > + </File> + <File + RelativePath="..\thirdparty\openjpeg-1.5.0\libopenjpeg\tcd.c" + > + </File> + <File + RelativePath="..\thirdparty\openjpeg-1.5.0\libopenjpeg\tgt.c" + > + </File> + <File + RelativePath="..\thirdparty\openjpeg-1.5.0\libopenjpeg\thix_manager.c" + > + </File> + <File + RelativePath="..\thirdparty\openjpeg-1.5.0\libopenjpeg\tpix_manager.c" > </File> </Filter> diff --git a/xps/muxps-internal.h b/xps/muxps-internal.h new file mode 100644 index 00000000..20bab4c1 --- /dev/null +++ b/xps/muxps-internal.h @@ -0,0 +1,242 @@ +#ifndef MUXPS_INTERNAL_H +#define MUXPS_INTERNAL_H + +#include "muxps.h" +#include "fitz-internal.h" + +typedef unsigned char byte; + +/* + * XPS and ZIP constants. + */ + +#define REL_START_PART \ + "http://schemas.microsoft.com/xps/2005/06/fixedrepresentation" +#define REL_DOC_STRUCTURE \ + "http://schemas.microsoft.com/xps/2005/06/documentstructure" +#define REL_REQUIRED_RESOURCE \ + "http://schemas.microsoft.com/xps/2005/06/required-resource" +#define REL_REQUIRED_RESOURCE_RECURSIVE \ + "http://schemas.microsoft.com/xps/2005/06/required-resource#recursive" + +#define ZIP_LOCAL_FILE_SIG 0x04034b50 +#define ZIP_DATA_DESC_SIG 0x08074b50 +#define ZIP_CENTRAL_DIRECTORY_SIG 0x02014b50 +#define ZIP_END_OF_CENTRAL_DIRECTORY_SIG 0x06054b50 + +/* + * Memory, and string functions. + */ + +int xps_strcasecmp(char *a, char *b); +void xps_resolve_url(char *output, char *base_uri, char *path, int output_size); +int xps_url_is_remote(char *path); +char *xps_parse_point(char *s_in, float *x, float *y); + +/* + * Container parts. + */ + +typedef struct xps_part_s xps_part; + +struct xps_part_s +{ + char *name; + int size; + int cap; + byte *data; +}; + +xps_part *xps_new_part(xps_document *doc, char *name, int size); +int xps_has_part(xps_document *doc, char *partname); +xps_part *xps_read_part(xps_document *doc, char *partname); +void xps_free_part(xps_document *doc, xps_part *part); + +/* + * Document structure. + */ + +typedef struct xps_fixdoc_s xps_fixdoc; +typedef struct xps_target_s xps_target; + +struct xps_fixdoc_s +{ + char *name; + char *outline; + xps_fixdoc *next; +}; + +struct xps_page_s +{ + char *name; + int number; + int width; + int height; + xml_element *root; + int links_resolved; + fz_link *links; + xps_page *next; +}; + +struct xps_target_s +{ + char *name; + int page; + xps_target *next; +}; + +void xps_read_page_list(xps_document *doc); +void xps_print_page_list(xps_document *doc); +void xps_free_page_list(xps_document *doc); + +int xps_count_pages(xps_document *doc); +xps_page *xps_load_page(xps_document *doc, int number); +fz_link *xps_load_links(xps_document *doc, xps_page *page); +fz_rect xps_bound_page(xps_document *doc, xps_page *page); +void xps_free_page(xps_document *doc, xps_page *page); + +fz_outline *xps_load_outline(xps_document *doc); + +int xps_lookup_link_target(xps_document *doc, char *target_uri); +void xps_add_link(xps_document *doc, fz_rect area, char *base_uri, char *target_uri); +/* + * Images, fonts, and colorspaces. + */ + +typedef struct xps_font_cache_s xps_font_cache; + +struct xps_font_cache_s +{ + char *name; + fz_font *font; + xps_font_cache *next; +}; + +typedef struct xps_glyph_metrics_s xps_glyph_metrics; + +struct xps_glyph_metrics_s +{ + float hadv, vadv, vorg; +}; + +int xps_count_font_encodings(fz_font *font); +void xps_identify_font_encoding(fz_font *font, int idx, int *pid, int *eid); +void xps_select_font_encoding(fz_font *font, int idx); +int xps_encode_font_char(fz_font *font, int key); + +void xps_measure_font_glyph(xps_document *doc, fz_font *font, int gid, xps_glyph_metrics *mtx); + +void xps_print_path(xps_document *doc); + +void xps_parse_color(xps_document *doc, char *base_uri, char *hexstring, fz_colorspace **csp, float *samples); +void xps_set_color(xps_document *doc, fz_colorspace *colorspace, float *samples); + +/* + * Resource dictionaries. + */ + +typedef struct xps_resource_s xps_resource; + +struct xps_resource_s +{ + char *name; + char *base_uri; /* only used in the head nodes */ + xml_element *base_xml; /* only used in the head nodes, to free the xml document */ + xml_element *data; + xps_resource *next; + xps_resource *parent; /* up to the previous dict in the stack */ +}; + +xps_resource * xps_parse_resource_dictionary(xps_document *doc, char *base_uri, xml_element *root); +void xps_free_resource_dictionary(xps_document *doc, xps_resource *dict); +void xps_resolve_resource_reference(xps_document *doc, xps_resource *dict, char **attp, xml_element **tagp, char **urip); + +void xps_print_resource_dictionary(xps_resource *dict); + +/* + * Fixed page/graphics parsing. + */ + +void xps_run_page(xps_document *doc, xps_page *page, fz_device *dev, fz_matrix ctm, fz_cookie *cookie); + +void xps_parse_fixed_page(xps_document *doc, fz_matrix ctm, xps_page *page); +void xps_parse_canvas(xps_document *doc, fz_matrix ctm, fz_rect area, char *base_uri, xps_resource *dict, xml_element *node); +void xps_parse_path(xps_document *doc, fz_matrix ctm, char *base_uri, xps_resource *dict, xml_element *node); +void xps_parse_glyphs(xps_document *doc, fz_matrix ctm, char *base_uri, xps_resource *dict, xml_element *node); +void xps_parse_solid_color_brush(xps_document *doc, fz_matrix ctm, char *base_uri, xps_resource *dict, xml_element *node); +void xps_parse_image_brush(xps_document *doc, fz_matrix ctm, fz_rect area, char *base_uri, xps_resource *dict, xml_element *node); +void xps_parse_visual_brush(xps_document *doc, fz_matrix ctm, fz_rect area, char *base_uri, xps_resource *dict, xml_element *node); +void xps_parse_linear_gradient_brush(xps_document *doc, fz_matrix ctm, fz_rect area, char *base_uri, xps_resource *dict, xml_element *node); +void xps_parse_radial_gradient_brush(xps_document *doc, fz_matrix ctm, fz_rect area, char *base_uri, xps_resource *dict, xml_element *node); + +void xps_parse_tiling_brush(xps_document *doc, fz_matrix ctm, fz_rect area, char *base_uri, xps_resource *dict, xml_element *root, void(*func)(xps_document*, fz_matrix, fz_rect, char*, xps_resource*, xml_element*, void*), void *user); + +void xps_parse_matrix_transform(xps_document *doc, xml_element *root, fz_matrix *matrix); +void xps_parse_render_transform(xps_document *doc, char *text, fz_matrix *matrix); +void xps_parse_rectangle(xps_document *doc, char *text, fz_rect *rect); + +void xps_begin_opacity(xps_document *doc, fz_matrix ctm, fz_rect area, char *base_uri, xps_resource *dict, char *opacity_att, xml_element *opacity_mask_tag); +void xps_end_opacity(xps_document *doc, char *base_uri, xps_resource *dict, char *opacity_att, xml_element *opacity_mask_tag); + +void xps_parse_brush(xps_document *doc, fz_matrix ctm, fz_rect area, char *base_uri, xps_resource *dict, xml_element *node); +void xps_parse_element(xps_document *doc, fz_matrix ctm, fz_rect area, char *base_uri, xps_resource *dict, xml_element *node); + +void xps_clip(xps_document *doc, fz_matrix ctm, xps_resource *dict, char *clip_att, xml_element *clip_tag); + +/* + * The interpreter context. + */ + +typedef struct xps_entry_s xps_entry; + +struct xps_entry_s +{ + char *name; + int offset; + int csize; + int usize; +}; + +struct xps_document_s +{ + fz_document super; + + fz_context *ctx; + char *directory; + fz_stream *file; + int zip_count; + xps_entry *zip_table; + + char *start_part; /* fixed document sequence */ + xps_fixdoc *first_fixdoc; /* first fixed document */ + xps_fixdoc *last_fixdoc; /* last fixed document */ + xps_page *first_page; /* first page of document */ + xps_page *last_page; /* last page of document */ + int page_count; + + xps_target *target; /* link targets */ + + char *base_uri; /* base uri for parsing XML and resolving relative paths */ + char *part_uri; /* part uri for parsing metadata relations */ + + /* We cache font resources */ + xps_font_cache *font_table; + + /* Opacity attribute stack */ + float opacity[64]; + int opacity_top; + + /* Current color */ + fz_colorspace *colorspace; + float color[8]; + float alpha; + + /* Current device */ + fz_cookie *cookie; + fz_device *dev; + + /* Current page we are loading */ + xps_page *current_page; +}; + +#endif diff --git a/xps/muxps.h b/xps/muxps.h index 6037a64e..a485adca 100644 --- a/xps/muxps.h +++ b/xps/muxps.h @@ -1,39 +1,10 @@ -#ifndef _MUXPS_H_ -#define _MUXPS_H_ +#ifndef MUXPS_H +#define MUXPS_H -#ifndef _FITZ_H_ -#error "fitz.h must be included before muxps.h" -#endif - -typedef unsigned char byte; - -/* - * XPS and ZIP constants. - */ +#include "fitz.h" typedef struct xps_document_s xps_document; - -#define REL_START_PART \ - "http://schemas.microsoft.com/xps/2005/06/fixedrepresentation" -#define REL_DOC_STRUCTURE \ - "http://schemas.microsoft.com/xps/2005/06/documentstructure" -#define REL_REQUIRED_RESOURCE \ - "http://schemas.microsoft.com/xps/2005/06/required-resource" -#define REL_REQUIRED_RESOURCE_RECURSIVE \ - "http://schemas.microsoft.com/xps/2005/06/required-resource#recursive" - -#define ZIP_LOCAL_FILE_SIG 0x04034b50 -#define ZIP_DATA_DESC_SIG 0x08074b50 -#define ZIP_CENTRAL_DIRECTORY_SIG 0x02014b50 -#define ZIP_END_OF_CENTRAL_DIRECTORY_SIG 0x06054b50 - -/* - * Memory, and string functions. - */ - -int xps_strcasecmp(char *a, char *b); -void xps_resolve_url(char *output, char *base_uri, char *path, int output_size); -int xps_url_is_remote(char *path); +typedef struct xps_page_s xps_page; /* * XML document model @@ -41,7 +12,7 @@ int xps_url_is_remote(char *path); typedef struct element xml_element; -xml_element *xml_parse_document(fz_context *doc, byte *buf, int len); +xml_element *xml_parse_document(fz_context *doc, unsigned char *buf, int len); xml_element *xml_next(xml_element *item); xml_element *xml_down(xml_element *item); char *xml_tag(xml_element *item); @@ -50,220 +21,48 @@ void xml_free_element(fz_context *doc, xml_element *item); void xml_print_element(xml_element *item, int level); /* - * Container parts. - */ + xps_open_document: Open a document. -typedef struct xps_part_s xps_part; + Open a document for reading so the library is able to locate + objects and pages inside the file. -struct xps_part_s -{ - char *name; - int size; - int cap; - byte *data; -}; + The returned xps_document should be used when calling most + other functions. Note that it wraps the context, so those + functions implicitly get access to the global state in + context. -xps_part *xps_new_part(xps_document *doc, char *name, int size); -int xps_has_part(xps_document *doc, char *partname); -xps_part *xps_read_part(xps_document *doc, char *partname); -void xps_free_part(xps_document *doc, xps_part *part); + filename: a path to a file as it would be given to open(2). +*/ +xps_document *xps_open_document(fz_context *ctx, char *filename); /* - * Document structure. - */ - -typedef struct xps_fixdoc_s xps_fixdoc; -typedef struct xps_page_s xps_page; -typedef struct xps_target_s xps_target; - -struct xps_fixdoc_s -{ - char *name; - char *outline; - xps_fixdoc *next; -}; + xps_open_document_with_stream: Opens a document. + + Same as xps_open_document, but takes a stream instead of a + filename to locate the document to open. Increments the + reference count of the stream. See fz_open_file, + fz_open_file_w or fz_open_fd for opening a stream, and + fz_close for closing an open stream. +*/ +xps_document *xps_open_document_with_stream(fz_stream *file); -struct xps_page_s -{ - char *name; - int number; - int width; - int height; - xml_element *root; - int links_resolved; - fz_link *links; - xps_page *next; -}; +/* + xps_close_document: Closes and frees an opened document. -struct xps_target_s -{ - char *name; - int page; - xps_target *next; -}; + The resource store in the context associated with xps_document + is emptied. -void xps_read_page_list(xps_document *doc); -void xps_debug_page_list(xps_document *doc); -void xps_free_page_list(xps_document *doc); + Does not throw exceptions. +*/ +void xps_close_document(xps_document *doc); int xps_count_pages(xps_document *doc); xps_page *xps_load_page(xps_document *doc, int number); -fz_link *xps_load_links(xps_document *doc, xps_page *page); fz_rect xps_bound_page(xps_document *doc, xps_page *page); +void xps_run_page(xps_document *doc, xps_page *page, fz_device *dev, fz_matrix ctm, fz_cookie *cookie); +fz_link *xps_load_links(xps_document *doc, xps_page *page); void xps_free_page(xps_document *doc, xps_page *page); fz_outline *xps_load_outline(xps_document *doc); -int xps_find_link_target(xps_document *doc, char *target_uri); -void xps_add_link(xps_document *doc, fz_rect area, char *base_uri, char *target_uri); -/* - * Images, fonts, and colorspaces. - */ - -typedef struct xps_font_cache_s xps_font_cache; - -struct xps_font_cache_s -{ - char *name; - fz_font *font; - xps_font_cache *next; -}; - -typedef struct xps_glyph_metrics_s xps_glyph_metrics; - -struct xps_glyph_metrics_s -{ - float hadv, vadv, vorg; -}; - -int xps_count_font_encodings(fz_font *font); -void xps_identify_font_encoding(fz_font *font, int idx, int *pid, int *eid); -void xps_select_font_encoding(fz_font *font, int idx); -int xps_encode_font_char(fz_font *font, int key); - -void xps_measure_font_glyph(xps_document *doc, fz_font *font, int gid, xps_glyph_metrics *mtx); - -void xps_debug_path(xps_document *doc); - -void xps_parse_color(xps_document *doc, char *base_uri, char *hexstring, fz_colorspace **csp, float *samples); -void xps_set_color(xps_document *doc, fz_colorspace *colorspace, float *samples); - -/* - * Resource dictionaries. - */ - -typedef struct xps_resource_s xps_resource; - -struct xps_resource_s -{ - char *name; - char *base_uri; /* only used in the head nodes */ - xml_element *base_xml; /* only used in the head nodes, to free the xml document */ - xml_element *data; - xps_resource *next; - xps_resource *parent; /* up to the previous dict in the stack */ -}; - -xps_resource * xps_parse_resource_dictionary(xps_document *doc, char *base_uri, xml_element *root); -void xps_free_resource_dictionary(xps_document *doc, xps_resource *dict); -void xps_resolve_resource_reference(xps_document *doc, xps_resource *dict, char **attp, xml_element **tagp, char **urip); - -void xps_debug_resource_dictionary(xps_resource *dict); - -/* - * Fixed page/graphics parsing. - */ - -void xps_run_page(xps_document *doc, xps_page *page, fz_device *dev, fz_matrix ctm, fz_cookie *cookie); - -void xps_parse_fixed_page(xps_document *doc, fz_matrix ctm, xps_page *page); -void xps_parse_canvas(xps_document *doc, fz_matrix ctm, fz_rect area, char *base_uri, xps_resource *dict, xml_element *node); -void xps_parse_path(xps_document *doc, fz_matrix ctm, char *base_uri, xps_resource *dict, xml_element *node); -void xps_parse_glyphs(xps_document *doc, fz_matrix ctm, char *base_uri, xps_resource *dict, xml_element *node); -void xps_parse_solid_color_brush(xps_document *doc, fz_matrix ctm, char *base_uri, xps_resource *dict, xml_element *node); -void xps_parse_image_brush(xps_document *doc, fz_matrix ctm, fz_rect area, char *base_uri, xps_resource *dict, xml_element *node); -void xps_parse_visual_brush(xps_document *doc, fz_matrix ctm, fz_rect area, char *base_uri, xps_resource *dict, xml_element *node); -void xps_parse_linear_gradient_brush(xps_document *doc, fz_matrix ctm, fz_rect area, char *base_uri, xps_resource *dict, xml_element *node); -void xps_parse_radial_gradient_brush(xps_document *doc, fz_matrix ctm, fz_rect area, char *base_uri, xps_resource *dict, xml_element *node); - -void xps_parse_tiling_brush(xps_document *doc, fz_matrix ctm, fz_rect area, char *base_uri, xps_resource *dict, xml_element *root, void(*func)(xps_document*, fz_matrix, fz_rect, char*, xps_resource*, xml_element*, void*), void *user); - -void xps_parse_matrix_transform(xps_document *doc, xml_element *root, fz_matrix *matrix); -void xps_parse_render_transform(xps_document *doc, char *text, fz_matrix *matrix); -void xps_parse_rectangle(xps_document *doc, char *text, fz_rect *rect); - -void xps_begin_opacity(xps_document *doc, fz_matrix ctm, fz_rect area, char *base_uri, xps_resource *dict, char *opacity_att, xml_element *opacity_mask_tag); -void xps_end_opacity(xps_document *doc, char *base_uri, xps_resource *dict, char *opacity_att, xml_element *opacity_mask_tag); - -void xps_parse_brush(xps_document *doc, fz_matrix ctm, fz_rect area, char *base_uri, xps_resource *dict, xml_element *node); -void xps_parse_element(xps_document *doc, fz_matrix ctm, fz_rect area, char *base_uri, xps_resource *dict, xml_element *node); - -void xps_clip(xps_document *doc, fz_matrix ctm, xps_resource *dict, char *clip_att, xml_element *clip_tag); - -/* - * The interpreter context. - */ - -typedef struct xps_entry_s xps_entry; - -struct xps_entry_s -{ - char *name; - int offset; - int csize; - int usize; -}; - -struct xps_document_s -{ - fz_document super; - - fz_context *ctx; - char *directory; - fz_stream *file; - int zip_count; - xps_entry *zip_table; - - char *start_part; /* fixed document sequence */ - xps_fixdoc *first_fixdoc; /* first fixed document */ - xps_fixdoc *last_fixdoc; /* last fixed document */ - xps_page *first_page; /* first page of document */ - xps_page *last_page; /* last page of document */ - int page_count; - - xps_target *target; /* link targets */ - - char *base_uri; /* base uri for parsing XML and resolving relative paths */ - char *part_uri; /* part uri for parsing metadata relations */ - - /* We cache font resources */ - xps_font_cache *font_table; - - /* Opacity attribute stack */ - float opacity[64]; - int opacity_top; - - /* Current color */ - fz_colorspace *colorspace; - float color[8]; - float alpha; - - /* Current device */ - fz_cookie *cookie; - fz_device *dev; - - /* Current page we are loading */ - xps_page *current_page; -}; - -xps_document *xps_open_document(fz_context *ctx, char *filename); -xps_document *xps_open_document_with_stream(fz_stream *file); -void xps_close_document(xps_document *doc); - -/* - * Parsing helper functions - */ -char *xps_get_real_params(char *s, int num, float *x); -char *xps_get_point(char *s_in, float *x, float *y); - #endif diff --git a/xps/xps_common.c b/xps/xps_common.c index 32ea3fdc..4829ef9c 100644 --- a/xps/xps_common.c +++ b/xps/xps_common.c @@ -1,5 +1,4 @@ -#include "fitz.h" -#include "muxps.h" +#include "muxps-internal.h" static inline int unhex(int a) { diff --git a/xps/xps_doc.c b/xps/xps_doc.c index d8ab7bf4..a2665f95 100644 --- a/xps/xps_doc.c +++ b/xps/xps_doc.c @@ -1,5 +1,4 @@ -#include "fitz.h" -#include "muxps.h" +#include "muxps-internal.h" static void xps_rels_for_part(char *buf, char *name, int buflen) @@ -21,7 +20,7 @@ xps_rels_for_part(char *buf, char *name, int buflen) */ void -xps_debug_page_list(xps_document *doc) +xps_print_page_list(xps_document *doc) { xps_fixdoc *fixdoc = doc->first_fixdoc; xps_page *page = doc->first_page; @@ -193,7 +192,7 @@ xps_add_link_target(xps_document *doc, char *name) } int -xps_find_link_target(xps_document *doc, char *target_uri) +xps_lookup_link_target(xps_document *doc, char *target_uri) { xps_target *target; char *needle = strrchr(target_uri, '#'); diff --git a/xps/xps_glyphs.c b/xps/xps_glyphs.c index f7098ed1..94baa918 100644 --- a/xps/xps_glyphs.c +++ b/xps/xps_glyphs.c @@ -1,5 +1,4 @@ -#include "fitz.h" -#include "muxps.h" +#include "muxps-internal.h" #include <ft2build.h> #include FT_FREETYPE_H @@ -307,7 +306,7 @@ xps_parse_glyphs_imp(xps_document *doc, fz_matrix ctm, { if (us && un > 0) { - int t = chartorune(&char_code, us); + int t = fz_chartorune(&char_code, us); us += t; un -= t; } } diff --git a/xps/xps_gradient.c b/xps/xps_gradient.c index f0ad0104..fe88b295 100644 --- a/xps/xps_gradient.c +++ b/xps/xps_gradient.c @@ -1,5 +1,4 @@ -#include "fitz.h" -#include "muxps.h" +#include "muxps-internal.h" #define MAX_STOPS 256 @@ -61,7 +60,7 @@ xps_parse_gradient_stops(xps_document *doc, char *base_uri, xml_element *node, xps_parse_color(doc, base_uri, color, &colorspace, sample); - fz_convert_color(doc->ctx, colorspace, sample + 1, fz_device_rgb, rgb); + fz_convert_color(doc->ctx, fz_device_rgb, rgb, colorspace, sample + 1); stops[count].r = rgb[0]; stops[count].g = rgb[1]; @@ -318,9 +317,9 @@ xps_draw_radial_gradient(xps_document *doc, fz_matrix ctm, yrad = 1.0; if (origin_att) - xps_get_point(origin_att, &x0, &y0); + xps_parse_point(origin_att, &x0, &y0); if (center_att) - xps_get_point(center_att, &x1, &y1); + xps_parse_point(center_att, &x1, &y1); if (radius_x_att) xrad = fz_atof(radius_x_att); if (radius_y_att) @@ -362,9 +361,9 @@ xps_draw_linear_gradient(xps_document *doc, fz_matrix ctm, x1 = y1 = 1; if (start_point_att) - xps_get_point(start_point_att, &x0, &y0); + xps_parse_point(start_point_att, &x0, &y0); if (end_point_att) - xps_get_point(end_point_att, &x1, &y1); + xps_parse_point(end_point_att, &x1, &y1); xps_draw_one_linear_gradient(doc, ctm, stops, count, 1, x0, y0, x1, y1); } diff --git a/xps/xps_image.c b/xps/xps_image.c index 10d3baee..1f46a756 100644 --- a/xps/xps_image.c +++ b/xps/xps_image.c @@ -1,41 +1,92 @@ -#include "fitz.h" -#include "muxps.h" +#include "muxps-internal.h" + +typedef struct xps_image_s xps_image; + +struct xps_image_s +{ + fz_image base; + fz_pixmap *pix; + int xres; + int yres; +}; + +static void +xps_free_image(fz_context *ctx, fz_storable *image_) +{ + xps_image *image = (xps_image *)image_; + + if (image == NULL) + return; + + fz_drop_colorspace(ctx, image->base.colorspace); + fz_drop_pixmap(ctx, image->pix); + fz_free(ctx, image); +} static fz_pixmap * +xps_image_to_pixmap(fz_context *ctx, fz_image *image_, int x, int w) +{ + xps_image *image = (xps_image *)image_; + + return fz_keep_pixmap(ctx, image->pix); +} + +static fz_image * xps_load_image(fz_context *ctx, byte *buf, int len) { - fz_pixmap *image; + fz_pixmap *pix; + xps_image *image; if (len < 8) fz_throw(ctx, "unknown image file format"); if (buf[0] == 0xff && buf[1] == 0xd8) - image = fz_load_jpeg(ctx, buf, len); + pix = fz_load_jpeg(ctx, buf, len); else if (memcmp(buf, "\211PNG\r\n\032\n", 8) == 0) - image = fz_load_png(ctx, buf, len); + pix = fz_load_png(ctx, buf, len); else if (memcmp(buf, "II", 2) == 0 && buf[2] == 0xBC) fz_throw(ctx, "JPEG-XR codec is not available"); else if (memcmp(buf, "MM", 2) == 0 || memcmp(buf, "II", 2) == 0) - image = fz_load_tiff(ctx, buf, len); + pix = fz_load_tiff(ctx, buf, len); else fz_throw(ctx, "unknown image file format"); - return image; + fz_try(ctx) + { + image = fz_malloc_struct(ctx, xps_image); + + FZ_INIT_STORABLE(&image->base, 1, xps_free_image); + image->base.w = pix->w; + image->base.h = pix->h; + image->base.mask = NULL; + image->base.colorspace = pix->colorspace; + image->base.get_pixmap = xps_image_to_pixmap; + image->xres = pix->xres; + image->yres = pix->yres; + image->pix = pix; + } + fz_catch(ctx) + { + fz_drop_pixmap(ctx, pix); + fz_rethrow(ctx); + } + + return &image->base; } static void xps_paint_image_brush(xps_document *doc, fz_matrix ctm, fz_rect area, char *base_uri, xps_resource *dict, xml_element *root, void *vimage) { - fz_pixmap *pixmap = vimage; + xps_image *image = vimage; float xs, ys; - if (pixmap->xres == 0 || pixmap->yres == 0) + if (image->xres == 0 || image->yres == 0) return; - xs = pixmap->w * 96 / pixmap->xres; - ys = pixmap->h * 96 / pixmap->yres; + xs = image->base.w * 96 / image->xres; + ys = image->base.h * 96 / image->yres; ctm = fz_concat(fz_scale(xs, ys), ctm); - fz_fill_image(doc->dev, pixmap, ctm, doc->opacity[doc->opacity_top]); + fz_fill_image(doc->dev, &image->base, ctm, doc->opacity[doc->opacity_top]); } static xps_part * @@ -93,7 +144,7 @@ xps_parse_image_brush(xps_document *doc, fz_matrix ctm, fz_rect area, char *base_uri, xps_resource *dict, xml_element *root) { xps_part *part; - fz_pixmap *image; + fz_image *image; fz_try(doc->ctx) { @@ -119,5 +170,5 @@ xps_parse_image_brush(xps_document *doc, fz_matrix ctm, fz_rect area, xps_parse_tiling_brush(doc, ctm, area, base_uri, dict, root, xps_paint_image_brush, image); - fz_drop_pixmap(doc->ctx, image); + fz_drop_image(doc->ctx, image); } diff --git a/xps/xps_outline.c b/xps/xps_outline.c index 30357491..6bf7fd14 100644 --- a/xps/xps_outline.c +++ b/xps/xps_outline.c @@ -1,5 +1,4 @@ -#include "fitz.h" -#include "muxps.h" +#include "muxps-internal.h" /* * Parse the document structure / outline parts referenced from fixdoc relationships. @@ -35,7 +34,7 @@ xps_parse_document_outline(xps_document *doc, xml_element *root) entry->title = fz_strdup(doc->ctx, description); entry->dest.kind = FZ_LINK_GOTO; entry->dest.ld.gotor.flags = 0; - entry->dest.ld.gotor.page = xps_find_link_target(doc, target); + entry->dest.ld.gotor.page = xps_lookup_link_target(doc, target); entry->down = NULL; entry->next = NULL; diff --git a/xps/xps_path.c b/xps/xps_path.c index 76b9bb21..337f144d 100644 --- a/xps/xps_path.c +++ b/xps/xps_path.c @@ -1,8 +1,7 @@ -#include "fitz.h" -#include "muxps.h" +#include "muxps-internal.h" -char * -xps_get_real_params(char *s, int num, float *x) +static char * +xps_parse_float_array(char *s, int num, float *x) { int k = 0; @@ -25,12 +24,12 @@ xps_get_real_params(char *s, int num, float *x) } char * -xps_get_point(char *s_in, float *x, float *y) +xps_parse_point(char *s_in, float *x, float *y) { char *s_out = s_in; float xy[2]; - s_out = xps_get_real_params(s_out, 2, &xy[0]); + s_out = xps_parse_float_array(s_out, 2, &xy[0]); *x = xy[0]; *y = xy[1]; return s_out; @@ -516,8 +515,8 @@ xps_parse_arc_segment(fz_context *doc, fz_path *path, xml_element *root, int str if (!is_stroked) *skipped_stroke = 1; - xps_get_point(point_att, &point_x, &point_y); - xps_get_point(size_att, &size_x, &size_y); + xps_parse_point(point_att, &point_x, &point_y); + xps_parse_point(size_att, &size_x, &size_y); rotation_angle = fz_atof(rotation_angle_att); is_large_arc = !strcmp(is_large_arc_att, "true"); is_clockwise = !strcmp(sweep_direction_att, "Clockwise"); @@ -559,7 +558,7 @@ xps_parse_poly_quadratic_bezier_segment(fz_context *doc, fz_path *path, xml_elem while (*s != 0) { while (*s == ' ') s++; - s = xps_get_point(s, &x[n], &y[n]); + s = xps_parse_point(s, &x[n], &y[n]); n ++; if (n == 2) { @@ -607,7 +606,7 @@ xps_parse_poly_bezier_segment(fz_context *doc, fz_path *path, xml_element *root, while (*s != 0) { while (*s == ' ') s++; - s = xps_get_point(s, &x[n], &y[n]); + s = xps_parse_point(s, &x[n], &y[n]); n ++; if (n == 3) { @@ -645,7 +644,7 @@ xps_parse_poly_line_segment(fz_context *doc, fz_path *path, xml_element *root, i while (*s != 0) { while (*s == ' ') s++; - s = xps_get_point(s, &x, &y); + s = xps_parse_point(s, &x, &y); if (stroking && !is_stroked) fz_moveto(doc, path, x, y); else @@ -678,7 +677,7 @@ xps_parse_path_figure(fz_context *doc, fz_path *path, xml_element *root, int str if (is_filled_att) is_filled = !strcmp(is_filled_att, "true"); if (start_point_att) - xps_get_point(start_point_att, &start_x, &start_y); + xps_parse_point(start_point_att, &start_x, &start_y); if (!stroking && !is_filled) /* not filled, when filling */ return; diff --git a/xps/xps_resource.c b/xps/xps_resource.c index dcf3717d..aa3cdc75 100644 --- a/xps/xps_resource.c +++ b/xps/xps_resource.c @@ -1,5 +1,4 @@ -#include "fitz.h" -#include "muxps.h" +#include "muxps-internal.h" static xml_element * xps_find_resource(xps_document *doc, xps_resource *dict, char *name, char **urip) @@ -142,7 +141,7 @@ xps_free_resource_dictionary(xps_document *doc, xps_resource *dict) } void -xps_debug_resource_dictionary(xps_resource *dict) +xps_print_resource_dictionary(xps_resource *dict) { while (dict) { @@ -152,7 +151,7 @@ xps_debug_resource_dictionary(xps_resource *dict) if (dict->parent) { printf("PARENT = {\n"); - xps_debug_resource_dictionary(dict->parent); + xps_print_resource_dictionary(dict->parent); printf("}\n"); } dict = dict->next; diff --git a/xps/xps_tile.c b/xps/xps_tile.c index e87d76f7..5ec0463f 100644 --- a/xps/xps_tile.c +++ b/xps/xps_tile.c @@ -1,5 +1,4 @@ -#include "fitz.h" -#include "muxps.h" +#include "muxps-internal.h" #define TILE diff --git a/xps/xps_util.c b/xps/xps_util.c index b79927ba..cb84ba71 100644 --- a/xps/xps_util.c +++ b/xps/xps_util.c @@ -1,5 +1,4 @@ -#include "fitz.h" -#include "muxps.h" +#include "muxps-internal.h" static inline int xps_tolower(int c) { diff --git a/xps/xps_xml.c b/xps/xps_xml.c index 15c510a6..e2e958c8 100644 --- a/xps/xps_xml.c +++ b/xps/xps_xml.c @@ -1,5 +1,4 @@ -#include "fitz.h" -#include "muxps.h" +#include "muxps-internal.h" struct attribute { @@ -185,7 +184,7 @@ static void xml_emit_att_value(struct parser *parser, char *a, char *b) while (a < b) { if (*a == '&') { a += xml_parse_entity(&c, a); - s += runetochar(s, &c); + s += fz_runetochar(s, c); } else { *s++ = *a++; @@ -340,7 +339,7 @@ static char *convert_to_utf8(fz_context *doc, unsigned char *s, int n) dst = d = fz_malloc(doc, n * 2); while (s + 1 < e) { c = s[0] << 8 | s[1]; - d += runetochar(d, &c); + d += fz_runetochar(d, c); s += 2; } *d = 0; @@ -351,7 +350,7 @@ static char *convert_to_utf8(fz_context *doc, unsigned char *s, int n) dst = d = fz_malloc(doc, n * 2); while (s + 1 < e) { c = s[0] | s[1] << 8; - d += runetochar(d, &c); + d += fz_runetochar(d, c); s += 2; } *d = 0; diff --git a/xps/xps_zip.c b/xps/xps_zip.c index 08d9832a..be7ae221 100644 --- a/xps/xps_zip.c +++ b/xps/xps_zip.c @@ -1,5 +1,4 @@ -#include "fitz.h" -#include "muxps.h" +#include "muxps-internal.h" #include <zlib.h> |