#include #include #include #include #include #include #include #include "fitz.h" #include "mupdf.h" #define LOG_TAG "libmupdf" #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) /* Set to 1 to enable debug log traces. */ #define DEBUG 0 /* Enable to log rendering times (render each frame 100 times and time) */ #undef TIME_DISPLAY_LIST /* Globals */ fz_colorspace *colorspace; fz_glyph_cache *glyphcache; pdf_xref *xref; int pagenum = 1; int resolution = 160; float pageWidth = 100; float pageHeight = 100; fz_display_list *currentPageList; fz_rect currentMediabox; int currentRotate; JNIEXPORT int JNICALL Java_com_artifex_mupdf_MuPDFCore_openFile(JNIEnv * env, jobject thiz, jstring jfilename) { const char *filename; char *password = ""; int accelerate = 1; fz_error error; int pages; filename = (*env)->GetStringUTFChars(env, jfilename, NULL); if (filename == NULL) { LOGE("Failed to get filename"); return 0; } if (accelerate) fz_accelerate(); glyphcache = fz_new_glyph_cache(); colorspace = fz_device_rgb; LOGE("Opening document..."); error = pdf_open_xref(&xref, filename, password); if (error) { LOGE("Cannot open document: '%s'\n", filename); return 0; } LOGE("Loading page tree..."); error = pdf_load_page_tree(xref); if (error) { LOGE("Cannot load page tree: '%s'\n", filename); return 0; } pages = pdf_count_pages(xref); LOGE("Done! %d pages", pages); return pages; } JNIEXPORT void JNICALL Java_com_artifex_mupdf_MuPDFCore_gotoPageInternal(JNIEnv *env, jobject thiz, int page) { float zoom; fz_matrix ctm; fz_bbox bbox; fz_error error; fz_device *dev; pdf_page *currentPage; /* In the event of an error, ensure we give a non-empty page */ pageWidth = 100; pageHeight = 100; LOGE("Goto page %d...", page); if (currentPageList != NULL) { fz_free_display_list(currentPageList); currentPageList = NULL; } pagenum = page; error = pdf_load_page(¤tPage, xref, pagenum); if (error) return; zoom = resolution / 72; currentMediabox = currentPage->mediabox; currentRotate = currentPage->rotate; ctm = fz_translate(0, -currentMediabox.y1); ctm = fz_concat(ctm, fz_scale(zoom, -zoom)); ctm = fz_concat(ctm, fz_rotate(currentRotate)); bbox = fz_round_rect(fz_transform_rect(ctm, currentMediabox)); pageWidth = bbox.x1-bbox.x0; pageHeight = bbox.y1-bbox.y0; /* Render to list */ currentPageList = fz_new_display_list(); dev = fz_new_list_device(currentPageList); error = pdf_run_page(xref, currentPage, dev, fz_identity); pdf_free_page(currentPage); if (error) LOGE("cannot make displaylist from page %d", pagenum); fz_free_device(dev); } JNIEXPORT float JNICALL Java_com_artifex_mupdf_MuPDFCore_getPageWidth(JNIEnv *env, jobject thiz) { LOGE("PageWidth=%g", pageWidth); return pageWidth; } JNIEXPORT float JNICALL Java_com_artifex_mupdf_MuPDFCore_getPageHeight(JNIEnv *env, jobject thiz) { LOGE("PageHeight=%g", pageHeight); return pageHeight; } JNIEXPORT jboolean JNICALL Java_com_artifex_mupdf_MuPDFCore_drawPage(JNIEnv *env, jobject thiz, jobject bitmap, int pageW, int pageH, int patchX, int patchY, int patchW, int patchH) { AndroidBitmapInfo info; void *pixels; int ret; fz_error error; fz_device *dev; float zoom; fz_matrix ctm; fz_bbox bbox; fz_pixmap *pix; float xscale, yscale; fz_bbox rect; LOGI("In native method\n"); if ((ret = AndroidBitmap_getInfo(env, bitmap, &info)) < 0) { LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret); return 0; } LOGI("Checking format\n"); if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888) { LOGE("Bitmap format is not RGBA_8888 !"); return 0; } LOGI("locking pixels\n"); if ((ret = AndroidBitmap_lockPixels(env, bitmap, &pixels)) < 0) { LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret); return 0; } /* Call mupdf to render display list to screen */ LOGE("Rendering page=%dx%d patch=[%d,%d,%d,%d]", pageW, pageH, patchX, patchY, patchW, patchH); rect.x0 = patchX; rect.y0 = patchY; rect.x1 = patchX + patchW; rect.y1 = patchY + patchH; pix = fz_new_pixmap_with_rect_and_data(colorspace, rect, pixels); if (currentPageList == NULL) { fz_clear_pixmap_with_color(pix, 0xd0); return 0; } fz_clear_pixmap_with_color(pix, 0xff); zoom = resolution / 72; ctm = fz_translate(-currentMediabox.x0, -currentMediabox.y1); ctm = fz_concat(ctm, fz_scale(zoom, -zoom)); ctm = fz_concat(ctm, fz_rotate(currentRotate)); bbox = fz_round_rect(fz_transform_rect(ctm,currentMediabox)); /* Now, adjust ctm so that it would give the correct page width * heights. */ xscale = (float)pageW/(float)(bbox.x1-bbox.x0); yscale = (float)pageH/(float)(bbox.y1-bbox.y0); ctm = fz_concat(ctm, fz_scale(xscale, yscale)); bbox = fz_round_rect(fz_transform_rect(ctm,currentMediabox)); dev = fz_new_draw_device(glyphcache, pix); #ifdef TIME_DISPLAY_LIST { clock_t time; int i; LOGE("Executing display list"); time = clock(); for (i=0; i<100;i++) { #endif fz_execute_display_list(currentPageList, dev, ctm, bbox); #ifdef TIME_DISPLAY_LIST } time = clock() - time; LOGE("100 renders in %d (%d per sec)", time, CLOCKS_PER_SEC); } #endif fz_free_device(dev); fz_drop_pixmap(pix); LOGE("Rendered"); AndroidBitmap_unlockPixels(env, bitmap); return 1; } JNIEXPORT void JNICALL Java_com_artifex_mupdf_MuPDFCore_destroying(JNIEnv * env, jobject thiz) { fz_free_display_list(currentPageList); currentPageList = NULL; pdf_free_xref(xref); xref = NULL; fz_free_glyph_cache(glyphcache); glyphcache = NULL; }