Render embedded annotations in PDF (#59)
* Added support for reading and displaying embedded PDF annotations. Changes include: - Added JNI bindings in `NativePdfiumBridge` and `pdfium_bridge.cpp` to extract annotation count, subtypes, rectangles, and string values (Contents, NM, IRT, T) using PDFium. - Introduced `EmbeddedAnnotation` data class to represent PDF annotations and their reply threads. - Implemented annotation extraction logic in `PdfPageComposable` to fetch, group, and map embedded annotations (Sticky Notes, Highlights, etc.) to screen coordinates. - Updated `PdfSelectionMenuPopup` to support displaying and copying comment threads. - Improved selection menu positioning and hit detection for annotations. - Added a safety check to recycle bitmaps in `PdfTile` rendering if handover to the main thread fails. * Improved comment thread UI
This commit is contained in:
parent
06ec45504f
commit
8582ed9679
4 changed files with 585 additions and 159 deletions
|
|
@ -1,19 +1,41 @@
|
|||
#include <jni.h>
|
||||
#include <dlfcn.h>
|
||||
#include <android/log.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#define LOG_TAG "PdfiumBridge"
|
||||
#define LOG_TAG "PdfiumAnnotation"
|
||||
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
|
||||
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
|
||||
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
|
||||
|
||||
typedef double (*FPDFText_GetFontSize_t)(void* text_page, int index);
|
||||
typedef int (*FPDFText_GetFontWeight_t)(void* text_page, int index);
|
||||
typedef int (*FPDFText_GetFontInfo_t)(void* text_page, int index, void* buffer, unsigned long buflen, int* flags);
|
||||
typedef int (*FPDFPage_GetAnnotCount_t)(void* page);
|
||||
typedef void* (*FPDFPage_GetAnnot_t)(void* page, int index);
|
||||
typedef int (*FPDFAnnot_GetSubtype_t)(void* annot);
|
||||
typedef int (*FPDFAnnot_GetRect_t)(void* annot, void* rect);
|
||||
typedef unsigned long (*FPDFAnnot_GetStringValue_t)(void* annot, const char* key, void* buffer, unsigned long buflen);
|
||||
typedef int (*FPDFAnnot_GetColor_t)(void* annot, int type, unsigned int* R, unsigned int* G, unsigned int* B, unsigned int* A);
|
||||
|
||||
static FPDFPage_GetAnnotCount_t get_annot_count_func = nullptr;
|
||||
static FPDFPage_GetAnnot_t get_annot_func = nullptr;
|
||||
static FPDFAnnot_GetSubtype_t get_annot_subtype_func = nullptr;
|
||||
static FPDFAnnot_GetRect_t get_annot_rect_func = nullptr;
|
||||
static FPDFAnnot_GetStringValue_t get_annot_string_func = nullptr;
|
||||
static FPDFAnnot_GetColor_t get_annot_color_func = nullptr;
|
||||
static void* pdfium_handle = nullptr;
|
||||
static FPDFText_GetFontSize_t get_font_size_func = nullptr;
|
||||
static FPDFText_GetFontWeight_t get_font_weight_func = nullptr;
|
||||
static FPDFText_GetFontInfo_t get_font_info_func = nullptr;
|
||||
|
||||
typedef void* (*FPDFAnnot_GetLinkedAnnot_t)(void* annot, const char* key);
|
||||
typedef void (*FPDFPage_CloseAnnot_t)(void* annot);
|
||||
|
||||
static FPDFAnnot_GetLinkedAnnot_t get_linked_annot_func = nullptr;
|
||||
static FPDFPage_CloseAnnot_t close_annot_func = nullptr;
|
||||
|
||||
static bool init_pdfium() {
|
||||
if (pdfium_handle) return true;
|
||||
|
||||
|
|
@ -27,7 +49,25 @@ static bool init_pdfium() {
|
|||
get_font_weight_func = (FPDFText_GetFontWeight_t) dlsym(pdfium_handle, "FPDFText_GetFontWeight");
|
||||
get_font_info_func = (FPDFText_GetFontInfo_t) dlsym(pdfium_handle, "FPDFText_GetFontInfo");
|
||||
|
||||
return get_font_size_func != nullptr && get_font_weight_func != nullptr && get_font_info_func != nullptr;
|
||||
get_annot_count_func = (FPDFPage_GetAnnotCount_t) dlsym(pdfium_handle, "FPDFPage_GetAnnotCount");
|
||||
get_annot_func = (FPDFPage_GetAnnot_t) dlsym(pdfium_handle, "FPDFPage_GetAnnot");
|
||||
get_annot_subtype_func = (FPDFAnnot_GetSubtype_t) dlsym(pdfium_handle, "FPDFAnnot_GetSubtype");
|
||||
get_annot_rect_func = (FPDFAnnot_GetRect_t) dlsym(pdfium_handle, "FPDFAnnot_GetRect");
|
||||
get_annot_string_func = (FPDFAnnot_GetStringValue_t) dlsym(pdfium_handle, "FPDFAnnot_GetStringValue");
|
||||
get_annot_color_func = (FPDFAnnot_GetColor_t) dlsym(pdfium_handle, "FPDFAnnot_GetColor");
|
||||
get_linked_annot_func = (FPDFAnnot_GetLinkedAnnot_t) dlsym(pdfium_handle, "FPDFAnnot_GetLinkedAnnot");
|
||||
close_annot_func = (FPDFPage_CloseAnnot_t) dlsym(pdfium_handle, "FPDFPage_CloseAnnot");
|
||||
|
||||
bool success = get_annot_count_func && get_annot_func && get_annot_subtype_func &&
|
||||
get_annot_rect_func && get_annot_string_func;
|
||||
|
||||
if (!success) {
|
||||
LOGE("Failed to find one or more annotation functions in libpdfium.so");
|
||||
} else {
|
||||
LOGI("Pdfium Annotation Bridge initialized successfully.");
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jdouble JNICALL
|
||||
|
|
@ -85,4 +125,71 @@ Java_com_aryan_reader_pdf_NativePdfiumBridge_getPageFontFlags(JNIEnv *env, jclas
|
|||
env->SetIntArrayRegion(result, 0, count, fill);
|
||||
delete[] fill;
|
||||
return result;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
Java_com_aryan_reader_pdf_NativePdfiumBridge_getAnnotCount(JNIEnv *env, jclass clazz, jlong pagePtr) {
|
||||
if (!init_pdfium() || !get_annot_count_func) return 0;
|
||||
return get_annot_count_func(reinterpret_cast<void*>(pagePtr));
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
Java_com_aryan_reader_pdf_NativePdfiumBridge_getAnnotSubtype(JNIEnv *env, jclass clazz, jlong pagePtr, jint index) {
|
||||
if (!init_pdfium() || !get_annot_func || !get_annot_subtype_func) return 0;
|
||||
void* annot = get_annot_func(reinterpret_cast<void*>(pagePtr), index);
|
||||
return annot ? get_annot_subtype_func(annot) : 0;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jfloatArray JNICALL
|
||||
Java_com_aryan_reader_pdf_NativePdfiumBridge_getAnnotRect(JNIEnv *env, jclass clazz, jlong pagePtr, jint index) {
|
||||
if (!init_pdfium() || !get_annot_func || !get_annot_rect_func) return nullptr;
|
||||
void* annot = get_annot_func(reinterpret_cast<void*>(pagePtr), index);
|
||||
if (!annot) return nullptr;
|
||||
|
||||
float rect[4];
|
||||
if (!get_annot_rect_func(annot, rect)) return nullptr;
|
||||
|
||||
jfloatArray result = env->NewFloatArray(4);
|
||||
env->SetFloatArrayRegion(result, 0, 4, rect);
|
||||
return result;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jstring JNICALL
|
||||
Java_com_aryan_reader_pdf_NativePdfiumBridge_getAnnotString(JNIEnv *env, jclass clazz, jlong pagePtr, jint index, jstring key) {
|
||||
if (!init_pdfium() || !get_annot_func || !get_annot_string_func) return nullptr;
|
||||
void* annot = get_annot_func(reinterpret_cast<void*>(pagePtr), index);
|
||||
if (!annot) return nullptr;
|
||||
|
||||
const char* nativeKey = env->GetStringUTFChars(key, nullptr);
|
||||
|
||||
if (strcmp(nativeKey, "IRT") == 0 && get_linked_annot_func && close_annot_func) {
|
||||
void* parentAnnot = get_linked_annot_func(annot, "IRT");
|
||||
if (parentAnnot) {
|
||||
unsigned long len = get_annot_string_func(parentAnnot, "NM", nullptr, 0);
|
||||
jstring result = nullptr;
|
||||
if (len > 2) {
|
||||
std::vector<unsigned short> buffer(len / 2);
|
||||
get_annot_string_func(parentAnnot, "NM", buffer.data(), len);
|
||||
result = env->NewString(reinterpret_cast<const jchar*>(buffer.data()), (jsize)(buffer.size() - 1));
|
||||
}
|
||||
close_annot_func(parentAnnot);
|
||||
env->ReleaseStringUTFChars(key, nativeKey);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long len = get_annot_string_func(annot, nativeKey, nullptr, 0);
|
||||
|
||||
if (len <= 2) {
|
||||
env->ReleaseStringUTFChars(key, nativeKey);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<unsigned short> buffer(len / 2);
|
||||
get_annot_string_func(annot, nativeKey, buffer.data(), len);
|
||||
|
||||
jstring result = env->NewString(reinterpret_cast<const jchar*>(buffer.data()), (jsize)(buffer.size() - 1));
|
||||
|
||||
env->ReleaseStringUTFChars(key, nativeKey);
|
||||
return result;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue