JNIEXPORT jboolean JNICALL JNI_FN(MuPDF_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_device *dev = NULL; float zoom; fz_matrix ctm; fz_irect bbox; fz_rect rect; fz_pixmap *pix = NULL; float xscale, yscale; globals *glo = get_globals(env, thiz); fz_context *ctx = glo->ctx; fz_document *doc = glo->doc; page_cache *pc = &glo->pages[glo->current]; int hq = (patchW < pageW || patchH < pageH); fz_matrix scale; if (pc->page == NULL) return 0; fz_var(pix); fz_var(dev); 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(%d)=%dx%d patch=[%d,%d,%d,%d]", pc->number, pageW, pageH, patchX, patchY, patchW, patchH); fz_try(ctx) { if (pc->page_list == NULL) { /* Render to list */ pc->page_list = fz_new_display_list(ctx); dev = fz_new_list_device(ctx, pc->page_list); fz_run_page_contents(doc, pc->page, dev, &fz_identity, NULL); } if (pc->annot_list == NULL) { fz_annot *annot; if (dev) { fz_free_device(dev); dev = NULL; } pc->annot_list = fz_new_display_list(ctx); dev = fz_new_list_device(ctx, pc->annot_list); for (annot = fz_first_annot(doc, pc->page); annot; annot = fz_next_annot(doc, annot)) fz_run_annot(doc, pc->page, annot, dev, &fz_identity, NULL); } bbox.x0 = patchX; bbox.y0 = patchY; bbox.x1 = patchX + patchW; bbox.y1 = patchY + patchH; pix = fz_new_pixmap_with_bbox_and_data(ctx, glo->colorspace, &bbox, pixels); if (pc->page_list == NULL && pc->annot_list == NULL) { fz_clear_pixmap_with_value(ctx, pix, 0xd0); break; } fz_clear_pixmap_with_value(ctx, pix, 0xff); zoom = glo->resolution / 72; fz_scale(&ctm, zoom, zoom); rect = pc->media_box; fz_round_rect(&bbox, fz_transform_rect(&rect, &ctm)); /* 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); fz_concat(&ctm, &ctm, fz_scale(&scale, xscale, yscale)); rect = pc->media_box; fz_transform_rect(&rect, &ctm); dev = fz_new_draw_device(ctx, pix); #ifdef TIME_DISPLAY_LIST { clock_t time; int i; LOGE("Executing display list"); time = clock(); for (i=0; i<100;i++) { #endif if (pc->page_list) fz_run_display_list(pc->page_list, dev, &ctm, &rect, NULL); if (pc->annot_list) fz_run_display_list(pc->annot_list, dev, &ctm, &rect, NULL); #ifdef TIME_DISPLAY_LIST } time = clock() - time; LOGE("100 renders in %d (%d per sec)", time, CLOCKS_PER_SEC); } #endif fz_free_device(dev); dev = NULL; fz_drop_pixmap(ctx, pix); LOGE("Rendered"); } fz_catch(ctx) { fz_free_device(dev); LOGE("Render failed"); } AndroidBitmap_unlockPixels(env, bitmap); return 1; }
JNIEXPORT jboolean JNICALL Java_com_artifex_mupdf_MuPDFCore_updatePageInternal(JNIEnv *env, jobject thiz, jobject bitmap, int page, int pageW, int pageH, int patchX, int patchY, int patchW, int patchH) { AndroidBitmapInfo info; void *pixels; int ret; fz_device *dev = NULL; float zoom; fz_matrix ctm; fz_bbox bbox; fz_pixmap *pix = NULL; float xscale, yscale; fz_bbox rect; fz_interactive *idoc; page_cache *pc = NULL; int hq = (patchW < pageW || patchH < pageH); int i; for (i = 0; i < NUM_CACHE; i++) { if (pages[i].page != NULL && pages[i].number == page) { pc = &pages[i]; break; } } if (pc == NULL || (hq && pc->hq_page == NULL)) { Java_com_artifex_mupdf_MuPDFCore_gotoPageInternal(env, thiz, page); return Java_com_artifex_mupdf_MuPDFCore_drawPage(env, thiz, bitmap, pageW, pageH, patchX, patchY, patchW, patchH); } idoc = fz_interact(doc); fz_var(pix); fz_var(dev); 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(%d)=%dx%d patch=[%d,%d,%d,%d]", pc->number, pageW, pageH, patchX, patchY, patchW, patchH); fz_try(ctx) { fz_annot *annot; // Unimportant which page object we use for rendering but we // must use the correct one for calculating updates fz_page *page = hq ? pc->hq_page : pc->page; fz_update_page(idoc, page); if (pc->page_list == NULL) { /* Render to list */ pc->page_list = fz_new_display_list(ctx); dev = fz_new_list_device(ctx, pc->page_list); fz_run_page_contents(doc, page, dev, fz_identity, NULL); } if (pc->annot_list == NULL) { if (dev) { fz_free_device(dev); dev = NULL; } pc->annot_list = fz_new_display_list(ctx); dev = fz_new_list_device(ctx, pc->annot_list); for (annot = fz_first_annot(doc, page); annot; annot = fz_next_annot(doc, annot)) fz_run_annot(doc, page, annot, dev, fz_identity, NULL); } rect.x0 = patchX; rect.y0 = patchY; rect.x1 = patchX + patchW; rect.y1 = patchY + patchH; pix = fz_new_pixmap_with_bbox_and_data(ctx, colorspace, rect, pixels); zoom = resolution / 72; ctm = fz_scale(zoom, zoom); bbox = fz_round_rect(fz_transform_rect(ctm, pc->media_box)); /* 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, pc->media_box)); LOGI("Start polling for updates"); while ((annot = fz_poll_changed_annot(idoc, page)) != NULL) { fz_bbox abox = fz_round_rect(fz_transform_rect(ctm, fz_bound_annot(doc, annot))); abox = fz_intersect_bbox(abox, rect); LOGI("Update rectanglefor %s - (%d, %d, %d, %d)", widget_type_string(fz_widget_get_type((fz_widget*)annot)), abox.x0, abox.y0, abox.x1, abox.y1); if (!fz_is_empty_bbox(abox)) { LOGI("And it isn't empty"); fz_clear_pixmap_rect_with_value(ctx, pix, 0xff, abox); dev = fz_new_draw_device_with_bbox(ctx, pix, abox); if (pc->page_list) fz_run_display_list(pc->page_list, dev, ctm, abox, NULL); if (pc->annot_list) fz_run_display_list(pc->annot_list, dev, ctm, abox, NULL); fz_free_device(dev); dev = NULL; } } LOGI("Done polling for updates"); LOGE("Rendered"); } fz_catch(ctx) { fz_free_device(dev); LOGE("Render failed"); } fz_drop_pixmap(ctx, pix); AndroidBitmap_unlockPixels(env, bitmap); return 1; }
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_device *dev = NULL; float zoom; fz_matrix ctm; fz_bbox bbox; fz_pixmap *pix = NULL; float xscale, yscale; fz_bbox rect; page_cache *pc = &pages[current]; int hq = (patchW < pageW || patchH < pageH); if (pc->page == NULL) return 0; fz_var(pix); fz_var(dev); 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(%d)=%dx%d patch=[%d,%d,%d,%d]", pc->number, pageW, pageH, patchX, patchY, patchW, patchH); fz_try(ctx) { fz_interactive *idoc = fz_interact(doc); // Call fz_update_page now to ensure future calls yield the // changes from the current state fz_update_page(idoc, pc->page); if (hq) { // This is a rendering of the hq patch. Ensure there's a second copy of the // page for use when updating this patch if (pc->hq_page) { if (idoc) fz_update_page(idoc, pc->hq_page); } else { // There is only ever one hq patch, so we need // cache only one page object for the sake of hq clear_hq_pages(); pc->hq_page = fz_load_page(doc, pc->number); } } if (pc->page_list == NULL) { /* Render to list */ pc->page_list = fz_new_display_list(ctx); dev = fz_new_list_device(ctx, pc->page_list); fz_run_page_contents(doc, pc->page, dev, fz_identity, NULL); } if (pc->annot_list == NULL) { fz_annot *annot; if (dev) { fz_free_device(dev); dev = NULL; } pc->annot_list = fz_new_display_list(ctx); dev = fz_new_list_device(ctx, pc->annot_list); for (annot = fz_first_annot(doc, pc->page); annot; annot = fz_next_annot(doc, annot)) fz_run_annot(doc, pc->page, annot, dev, fz_identity, NULL); } rect.x0 = patchX; rect.y0 = patchY; rect.x1 = patchX + patchW; rect.y1 = patchY + patchH; pix = fz_new_pixmap_with_bbox_and_data(ctx, colorspace, rect, pixels); if (pc->page_list == NULL && pc->annot_list == NULL) { fz_clear_pixmap_with_value(ctx, pix, 0xd0); break; } fz_clear_pixmap_with_value(ctx, pix, 0xff); zoom = resolution / 72; ctm = fz_scale(zoom, zoom); bbox = fz_round_rect(fz_transform_rect(ctm, pc->media_box)); /* 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, pc->media_box)); dev = fz_new_draw_device(ctx, pix); #ifdef TIME_DISPLAY_LIST { clock_t time; int i; LOGE("Executing display list"); time = clock(); for (i=0; i<100;i++) { #endif if (pc->page_list) fz_run_display_list(pc->page_list, dev, ctm, bbox, NULL); if (pc->annot_list) fz_run_display_list(pc->annot_list, dev, ctm, bbox, NULL); #ifdef TIME_DISPLAY_LIST } time = clock() - time; LOGE("100 renders in %d (%d per sec)", time, CLOCKS_PER_SEC); } #endif fz_free_device(dev); dev = NULL; fz_drop_pixmap(ctx, pix); LOGE("Rendered"); } fz_catch(ctx) { fz_free_device(dev); LOGE("Render failed"); } AndroidBitmap_unlockPixels(env, bitmap); return 1; }
HRESULT MuPDFDoc::DrawPage(unsigned char *bitmap, int x, int y, int width, int height, bool invert) { m_cts->abort = 0; fz_device *dev = nullptr; fz_pixmap *pixmap = nullptr; fz_var(dev); fz_var(pixmap); PageCache *pageCache = &m_pages[m_currentPage]; fz_try(m_context) { fz_interactive *idoc = fz_interact(m_document); // Call fz_update_page now to ensure future calls yield the // changes from the current state if (idoc) fz_update_page(idoc, pageCache->page); if (!pageCache->pageList) { /* Render to list */ pageCache->pageList = fz_new_display_list(m_context); dev = fz_new_list_device(m_context, pageCache->pageList); fz_run_page_contents(m_document, pageCache->page, dev, fz_identity, *&m_cts); } if (!pageCache->annotList) { if (dev) { fz_free_device(dev); dev = nullptr; } pageCache->annotList = fz_new_display_list(m_context); dev = fz_new_list_device(m_context, pageCache->annotList); for (fz_annot *annot = fz_first_annot(m_document, pageCache->page); annot; annot = fz_next_annot(m_document, annot)) fz_run_annot(m_document, pageCache->page, annot, dev, fz_identity, *&m_cts); } fz_bbox rect; rect.x0 = x; rect.y0 = y; rect.x1 = x + width; rect.y1 = y + height; pixmap = fz_new_pixmap_with_bbox_and_data(m_context, fz_device_bgr, rect, bitmap); if (!pageCache->pageList && !pageCache->annotList) { fz_clear_pixmap_with_value(m_context, pixmap, 0xd0); break; } fz_clear_pixmap_with_value(m_context, pixmap, 0xff); // fz_matrix ctm = CalcConvertMatrix(); fz_bbox bbox = fz_round_rect(fz_transform_rect(ctm, pageCache->mediaBox)); /* Now, adjust ctm so that it would give the correct page width * heights. */ float xscale = (float)width/(float)(bbox.x1-bbox.x0); float yscale = (float)height/(float)(bbox.y1-bbox.y0); ctm = fz_concat(ctm, fz_scale(xscale, yscale)); bbox = fz_round_rect(fz_transform_rect(ctm, pageCache->mediaBox)); if (dev) { fz_free_device(dev); dev = nullptr; } dev = fz_new_draw_device(m_context, pixmap); if (pageCache->pageList) fz_run_display_list(pageCache->pageList, dev, ctm, bbox, *&m_cts); about = m_cts->abort; if (pageCache->annotList) fz_run_display_list(pageCache->annotList, dev, ctm, bbox, *&m_cts); if (invert) fz_invert_pixmap(m_context, pixmap); } fz_always(m_context) { if (dev) { fz_free_device(dev); dev = nullptr; } if (pixmap) { fz_drop_pixmap(m_context, pixmap); } } fz_catch(m_context) { return E_FAIL; } return S_OK; }
HRESULT MuPDFDoc::UpdatePage(int pageNumber, unsigned char *bitmap, int x, int y, int width, int height, bool invert) { int index = FindPageInCache(pageNumber); if (index < 0) { //TODO: get rid of this side effect!!! HRESULT result = GotoPage(pageNumber); if (FAILED(result)) { return result; } return DrawPage(bitmap, x, y, width, height, invert); } fz_device *dev = nullptr; fz_pixmap *pixmap = nullptr; fz_var(dev); fz_var(pixmap); PageCache *pageCache = &m_pages[m_currentPage]; fz_try(m_context) { fz_interactive *idoc = fz_interact(m_document); // Call fz_update_page now to ensure future calls yield the // changes from the current state if (idoc) fz_update_page(idoc, pageCache->page); if (!pageCache->pageList) { /* Render to list */ pageCache->pageList = fz_new_display_list(m_context); dev = fz_new_list_device(m_context, pageCache->pageList); fz_run_page_contents(m_document, pageCache->page, dev, fz_identity, nullptr); } if (!pageCache->annotList) { if (dev) { fz_free_device(dev); dev = nullptr; } pageCache->annotList = fz_new_display_list(m_context); dev = fz_new_list_device(m_context, pageCache->annotList); for (fz_annot *annot = fz_first_annot(m_document, pageCache->page); annot; annot = fz_next_annot(m_document, annot)) fz_run_annot(m_document, pageCache->page, annot, dev, fz_identity, nullptr); } fz_bbox rect; rect.x0 = x; rect.y0 = y; rect.x1 = x + width; rect.y1 = y + height; pixmap = fz_new_pixmap_with_bbox_and_data(m_context, fz_device_bgr, rect, bitmap); // fz_matrix ctm = CalcConvertMatrix(); fz_bbox bbox = fz_round_rect(fz_transform_rect(ctm, pageCache->mediaBox)); /* Now, adjust ctm so that it would give the correct page width * heights. */ float xscale = (float)width/(float)(bbox.x1-bbox.x0); float yscale = (float)height/(float)(bbox.y1-bbox.y0); ctm = fz_concat(ctm, fz_scale(xscale, yscale)); bbox = fz_round_rect(fz_transform_rect(ctm, pageCache->mediaBox)); if (dev) { fz_free_device(dev); dev = nullptr; } fz_annot *annot; while (idoc && (annot = fz_poll_changed_annot(idoc, pageCache->page))) { fz_bbox abox = fz_round_rect(fz_transform_rect(ctm, fz_bound_annot(m_document, annot))); abox = fz_intersect_bbox(abox, rect); if (!fz_is_empty_bbox(abox)) { fz_clear_pixmap_rect_with_value(m_context, pixmap, 0xff, abox); dev = fz_new_draw_device_with_bbox(m_context, pixmap, abox); if (pageCache->pageList) fz_run_display_list(pageCache->pageList, dev, ctm, abox, nullptr); if (pageCache->annotList) fz_run_display_list(pageCache->annotList, dev, ctm, abox, nullptr); fz_free_device(dev); dev = nullptr; if (invert) fz_invert_pixmap_rect(pixmap, abox); } } } fz_always(m_context) { if (dev) { fz_free_device(dev); dev = nullptr; } if (pixmap) { fz_drop_pixmap(m_context, pixmap); } } fz_catch(m_context) { return E_FAIL; } return S_OK; }
HRESULT MuPDFDoc::LoadTwoPages(unsigned char *bitmap1, int pageNum1, unsigned char *bitmap2, int pageNum2, int width, int height, Data **data1, Data **data2) { GotoPage(pageNum1); fz_device *dev = nullptr; fz_pixmap *pixmap = nullptr; fz_var(dev); fz_var(pixmap); PageCache *pageCache = &m_pages[m_currentPage]; fz_try(m_context) { m_cts->abort = 0; fz_interactive *idoc = fz_interact(m_document); // Call fz_update_page now to ensure future calls yield the // changes from the current state if (idoc) fz_update_page(idoc, pageCache->page); if (!pageCache->pageList) { /* Render to list */ pageCache->pageList = fz_new_display_list(m_context); dev = fz_new_list_device(m_context, pageCache->pageList); fz_run_page_contents(m_document, pageCache->page, dev, fz_identity, nullptr); } if (!pageCache->annotList) { if (dev) { fz_free_device(dev); dev = nullptr; } pageCache->annotList = fz_new_display_list(m_context); dev = fz_new_list_device(m_context, pageCache->annotList); for (fz_annot *annot = fz_first_annot(m_document, pageCache->page); annot; annot = fz_next_annot(m_document, annot)) fz_run_annot(m_document, pageCache->page, annot, dev, fz_identity, nullptr); } fz_bbox rect; rect.x0 = 0; rect.y0 = 0; rect.x1 = width; rect.y1 = height; pixmap = fz_new_pixmap_with_bbox_and_data(m_context, fz_device_bgr, rect, bitmap1); if (!pageCache->pageList && !pageCache->annotList) { fz_clear_pixmap_with_value(m_context, pixmap, 0xd0); break; } fz_clear_pixmap_with_value(m_context, pixmap, 0xff); *data1 = (Data*)CoTaskMemAlloc(sizeof(Data)); (*data1)->pagenumber = pageNum1; (*data1)->cacheNumber = m_currentPage; (*data1)->ctx = m_context; (*data1)->list = pageCache->pageList; (*data1)->annotList = pageCache->annotList; (*data1)->bbox = rect; (*data1)->rect = pageCache->mediaBox; (*data1)->pix = pixmap; (*data1)->width = width; (*data1)->height = height; } fz_catch(m_context) { return E_FAIL; } GotoPage(pageNum2); fz_device *dev1 = nullptr; fz_pixmap *pixmap1 = nullptr; fz_var(dev1); fz_var(pixmap1); PageCache *pageCache1 = &m_pages[m_currentPage]; fz_try(m_context) { fz_interactive *idoc = fz_interact(m_document); // Call fz_update_page now to ensure future calls yield the // changes from the current state if (idoc) fz_update_page(idoc, pageCache1->page); if (!pageCache1->pageList) { /* Render to list */ pageCache1->pageList = fz_new_display_list(m_context); dev1 = fz_new_list_device(m_context, pageCache1->pageList); fz_run_page_contents(m_document, pageCache1->page, dev1, fz_identity, nullptr); } if (!pageCache1->annotList) { if (dev1) { fz_free_device(dev1); dev1 = nullptr; } pageCache1->annotList = fz_new_display_list(m_context); dev1 = fz_new_list_device(m_context, pageCache1->annotList); for (fz_annot *annot = fz_first_annot(m_document, pageCache1->page); annot; annot = fz_next_annot(m_document, annot)) fz_run_annot(m_document, pageCache1->page, annot, dev1, fz_identity, nullptr); } fz_bbox rect; rect.x0 = 0; rect.y0 = 0; rect.x1 = width; rect.y1 = height; pixmap1 = fz_new_pixmap_with_bbox_and_data(m_context, fz_device_bgr, rect, bitmap2); if (!pageCache1->pageList && !pageCache1->annotList) { fz_clear_pixmap_with_value(m_context, pixmap1, 0xd0); break; } fz_clear_pixmap_with_value(m_context, pixmap1, 0xff); *data2 = (Data*)CoTaskMemAlloc(sizeof(Data)); (*data2)->pagenumber = pageNum2; (*data2)->cacheNumber = m_currentPage; (*data2)->ctx = m_context; (*data2)->list = pageCache1->pageList; (*data2)->annotList = pageCache->annotList; (*data2)->bbox = rect; (*data2)->rect = pageCache1->mediaBox; (*data2)->pix = pixmap1; (*data2)->width = width; (*data2)->height = height; } fz_catch(m_context) { return E_FAIL; } return S_OK; }