Pdf reflow upgrade (#63)
* Replaced PDF-to-Markdown reflow with an enhanced PDF-to-HTML generator. Specific changes include: - Replaced `PdfToMarkdownGenerator` and `PdfReflowGenerator` with `PdfToHtmlGenerator`. - Added native bridge methods in `NativePdfiumBridge.kt` and `pdfium_bridge.cpp` to extract character bounding boxes, page objects, and image pixels. - Implemented vertical merging of text and images in `PdfToHtmlGenerator` to maintain document layout. - Added logic to detect and filter repeating headers and footers across PDF pages. - Updated `ReflowWorker` to generate `.html` files instead of `.md` files and updated `FileType` handling. - Simplified `SingleFileImporter` by removing dependencies on the legacy Markdown generator. * Updated PDF to HTML generation to include page breaks and split HTML files into individual chapters based on page markers. * Added junk character filtering and normalization to PDF text extraction * - Added `allRecentFiles` to `ReaderScreenState` to track all files, including reflowed versions. - Updated `recentFiles` in `MainViewModel` to filter out reflowed files (`_reflow`) from the main library view. - Implemented `deleteBookPermanently` in `MainViewModel` to handle book deletion and cache cleanup. - Added a "Delete Text View" option to the `EpubReader` controls for reflowed files. - Improved reflow file detection in `PdfViewerScreen` by checking against `allRecentFiles`. * Implemented a centralized data-saving mechanism in `PdfViewerScreen` using a debounced `saveAllData` function. This refactor consolidates the saving of annotations, text boxes, highlights, bookmarks, and scroll positions, adding lifecycle-aware triggers and a mutex to ensure data integrity during pauses or document navigation. * Optimized PDF selection and annotation performance by offloading heavy operations to background threads and improving UI responsiveness. - Moved PDF page/text opening, character range calculations, and text extraction to `Dispatchers.IO`. - Wrapped UI updates in `updateSelectionVisuals` and selection logic with `withContext(Dispatchers.Main)`. - Implemented a more efficient `Popup`-based magnifier to replace manual offsets and transformations. - Updated `PdfSelectionMenuPopup` properties to prevent focus and click-outside dismissal conflicts.
This commit is contained in:
parent
9a95b4afcd
commit
843a77d0ef
13 changed files with 1270 additions and 895 deletions
|
|
@ -12,13 +12,34 @@
|
|||
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 (*FPDFText_GetCharBox_t)(void* text_page, int index, double* left, double* right, double* bottom, double* top);
|
||||
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);
|
||||
typedef int (*FPDFPage_CountObjects_t)(void* page);
|
||||
typedef void* (*FPDFPage_GetObject_t)(void* page, int index);
|
||||
typedef int (*FPDFPageObj_GetType_t)(void* page_object);
|
||||
typedef void* (*FPDFImageObj_GetBitmap_t)(void* image_object);
|
||||
typedef int (*FPDFBitmap_GetWidth_t)(void* bitmap);
|
||||
typedef int (*FPDFBitmap_GetHeight_t)(void* bitmap);
|
||||
typedef int (*FPDFBitmap_GetStride_t)(void* bitmap);
|
||||
typedef void* (*FPDFBitmap_GetBuffer_t)(void* bitmap);
|
||||
typedef void (*FPDFBitmap_Destroy_t)(void* bitmap);
|
||||
typedef int (*FPDFPageObj_GetBounds_t)(void* page_object, float* left, float* bottom, float* right, float* top);
|
||||
|
||||
static FPDFPage_CountObjects_t count_objects_func = nullptr;
|
||||
static FPDFPage_GetObject_t get_object_func = nullptr;
|
||||
static FPDFPageObj_GetType_t get_object_type_func = nullptr;
|
||||
static FPDFImageObj_GetBitmap_t get_image_bitmap_func = nullptr;
|
||||
static FPDFBitmap_GetWidth_t bitmap_get_width_func = nullptr;
|
||||
static FPDFBitmap_GetHeight_t bitmap_get_height_func = nullptr;
|
||||
static FPDFBitmap_GetStride_t bitmap_get_stride_func = nullptr;
|
||||
static FPDFBitmap_GetBuffer_t bitmap_get_buffer_func = nullptr;
|
||||
static FPDFBitmap_Destroy_t bitmap_destroy_func = nullptr;
|
||||
static FPDFPageObj_GetBounds_t get_object_bounds_func = nullptr;
|
||||
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;
|
||||
|
|
@ -29,6 +50,7 @@ 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;
|
||||
static FPDFText_GetCharBox_t get_char_box_func = nullptr;
|
||||
|
||||
typedef void* (*FPDFAnnot_GetLinkedAnnot_t)(void* annot, const char* key);
|
||||
typedef void (*FPDFPage_CloseAnnot_t)(void* annot);
|
||||
|
|
@ -48,6 +70,7 @@ static bool init_pdfium() {
|
|||
get_font_size_func = (FPDFText_GetFontSize_t) dlsym(pdfium_handle, "FPDFText_GetFontSize");
|
||||
get_font_weight_func = (FPDFText_GetFontWeight_t) dlsym(pdfium_handle, "FPDFText_GetFontWeight");
|
||||
get_font_info_func = (FPDFText_GetFontInfo_t) dlsym(pdfium_handle, "FPDFText_GetFontInfo");
|
||||
get_char_box_func = (FPDFText_GetCharBox_t) dlsym(pdfium_handle, "FPDFText_GetCharBox");
|
||||
|
||||
get_annot_count_func = (FPDFPage_GetAnnotCount_t) dlsym(pdfium_handle, "FPDFPage_GetAnnotCount");
|
||||
get_annot_func = (FPDFPage_GetAnnot_t) dlsym(pdfium_handle, "FPDFPage_GetAnnot");
|
||||
|
|
@ -58,6 +81,17 @@ static bool init_pdfium() {
|
|||
get_linked_annot_func = (FPDFAnnot_GetLinkedAnnot_t) dlsym(pdfium_handle, "FPDFAnnot_GetLinkedAnnot");
|
||||
close_annot_func = (FPDFPage_CloseAnnot_t) dlsym(pdfium_handle, "FPDFPage_CloseAnnot");
|
||||
|
||||
count_objects_func = (FPDFPage_CountObjects_t) dlsym(pdfium_handle, "FPDFPage_CountObjects");
|
||||
get_object_func = (FPDFPage_GetObject_t) dlsym(pdfium_handle, "FPDFPage_GetObject");
|
||||
get_object_type_func = (FPDFPageObj_GetType_t) dlsym(pdfium_handle, "FPDFPageObj_GetType");
|
||||
get_image_bitmap_func = (FPDFImageObj_GetBitmap_t) dlsym(pdfium_handle, "FPDFImageObj_GetBitmap");
|
||||
bitmap_get_width_func = (FPDFBitmap_GetWidth_t) dlsym(pdfium_handle, "FPDFBitmap_GetWidth");
|
||||
bitmap_get_height_func = (FPDFBitmap_GetHeight_t) dlsym(pdfium_handle, "FPDFBitmap_GetHeight");
|
||||
bitmap_get_stride_func = (FPDFBitmap_GetStride_t) dlsym(pdfium_handle, "FPDFBitmap_GetStride");
|
||||
bitmap_get_buffer_func = (FPDFBitmap_GetBuffer_t) dlsym(pdfium_handle, "FPDFBitmap_GetBuffer");
|
||||
bitmap_destroy_func = (FPDFBitmap_Destroy_t) dlsym(pdfium_handle, "FPDFBitmap_Destroy");
|
||||
get_object_bounds_func = (FPDFPageObj_GetBounds_t) dlsym(pdfium_handle, "FPDFPageObj_GetBounds");
|
||||
|
||||
bool success = get_annot_count_func && get_annot_func && get_annot_subtype_func &&
|
||||
get_annot_rect_func && get_annot_string_func;
|
||||
|
||||
|
|
@ -127,6 +161,27 @@ Java_com_aryan_reader_pdf_NativePdfiumBridge_getPageFontFlags(JNIEnv *env, jclas
|
|||
return result;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jfloatArray JNICALL
|
||||
Java_com_aryan_reader_pdf_NativePdfiumBridge_getPageCharBoxes(JNIEnv *env, jclass clazz, jlong textPagePtr, jint count) {
|
||||
if (!init_pdfium() || !get_char_box_func || count <= 0) return nullptr;
|
||||
|
||||
const int stride = 4;
|
||||
jfloatArray result = env->NewFloatArray(count * stride);
|
||||
jfloat *fill = new jfloat[count * stride];
|
||||
void* tp = reinterpret_cast<void*>(textPagePtr);
|
||||
for (int i = 0; i < count; i++) {
|
||||
double left = 0, right = 0, bottom = 0, top = 0;
|
||||
get_char_box_func(tp, i, &left, &right, &bottom, &top);
|
||||
fill[i * stride + 0] = (jfloat)left;
|
||||
fill[i * stride + 1] = (jfloat)bottom;
|
||||
fill[i * stride + 2] = (jfloat)right;
|
||||
fill[i * stride + 3] = (jfloat)top;
|
||||
}
|
||||
env->SetFloatArrayRegion(result, 0, count * stride, 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;
|
||||
|
|
@ -191,5 +246,84 @@ Java_com_aryan_reader_pdf_NativePdfiumBridge_getAnnotString(JNIEnv *env, jclass
|
|||
jstring result = env->NewString(reinterpret_cast<const jchar*>(buffer.data()), (jsize)(buffer.size() - 1));
|
||||
|
||||
env->ReleaseStringUTFChars(key, nativeKey);
|
||||
return result;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
Java_com_aryan_reader_pdf_NativePdfiumBridge_getPageObjectCount(JNIEnv *env, jclass clazz, jlong pagePtr) {
|
||||
if (!init_pdfium() || !count_objects_func) return 0;
|
||||
return count_objects_func(reinterpret_cast<void*>(pagePtr));
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
Java_com_aryan_reader_pdf_NativePdfiumBridge_getPageObjectType(JNIEnv *env, jclass clazz, jlong pagePtr, jint index) {
|
||||
if (!init_pdfium() || !get_object_func || !get_object_type_func) return 0;
|
||||
void* obj = get_object_func(reinterpret_cast<void*>(pagePtr), index);
|
||||
return obj ? get_object_type_func(obj) : 0;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL
|
||||
Java_com_aryan_reader_pdf_NativePdfiumBridge_getPageObjectBoundingBox(JNIEnv *env, jclass clazz, jlong pagePtr, jint index, jfloatArray outRect) {
|
||||
if (!init_pdfium() || !get_object_func || !get_object_bounds_func) return JNI_FALSE;
|
||||
void* obj = get_object_func(reinterpret_cast<void*>(pagePtr), index);
|
||||
if (!obj) return JNI_FALSE;
|
||||
|
||||
float left = 0, bottom = 0, right = 0, top = 0;
|
||||
if (get_object_bounds_func(obj, &left, &bottom, &right, &top)) {
|
||||
jfloat rect[4] = {left, bottom, right, top};
|
||||
env->SetFloatArrayRegion(outRect, 0, 4, rect);
|
||||
return JNI_TRUE;
|
||||
}
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jintArray JNICALL
|
||||
Java_com_aryan_reader_pdf_NativePdfiumBridge_extractImagePixels(JNIEnv *env, jclass clazz, jlong pagePtr, jint index, jintArray dimens) {
|
||||
if (!init_pdfium() || !get_object_func || !get_image_bitmap_func || !bitmap_get_buffer_func) return nullptr;
|
||||
|
||||
void* obj = get_object_func(reinterpret_cast<void*>(pagePtr), index);
|
||||
if (!obj || get_object_type_func(obj) != 3) return nullptr; // 3 = FPDF_PAGEOBJ_IMAGE
|
||||
|
||||
void* bmp = get_image_bitmap_func(obj);
|
||||
if (!bmp) return nullptr;
|
||||
|
||||
int w = bitmap_get_width_func(bmp);
|
||||
int h = bitmap_get_height_func(bmp);
|
||||
int stride = bitmap_get_stride_func(bmp);
|
||||
uint8_t* buffer = (uint8_t*)bitmap_get_buffer_func(bmp);
|
||||
|
||||
if (!buffer || w <= 0 || h <= 0) {
|
||||
bitmap_destroy_func(bmp);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
jintArray result = env->NewIntArray(w * h);
|
||||
jint* pixels = new jint[w * h];
|
||||
int bpp = stride / w;
|
||||
|
||||
for (int y = 0; y < h; y++) {
|
||||
uint8_t* row = buffer + y * stride;
|
||||
for (int x = 0; x < w; x++) {
|
||||
uint8_t r = 0, g = 0, b = 0, a = 255;
|
||||
if (bpp >= 3) {
|
||||
b = row[x * bpp + 0];
|
||||
g = row[x * bpp + 1];
|
||||
r = row[x * bpp + 2];
|
||||
if (bpp >= 4) a = row[x * bpp + 3];
|
||||
} else if (bpp == 1) {
|
||||
r = g = b = row[x];
|
||||
}
|
||||
// Pack pixels for Android ARGB_8888
|
||||
pixels[y * w + x] = (a << 24) | (r << 16) | (g << 8) | b;
|
||||
}
|
||||
}
|
||||
|
||||
env->SetIntArrayRegion(result, 0, w * h, pixels);
|
||||
delete[] pixels;
|
||||
bitmap_destroy_func(bmp);
|
||||
|
||||
jint dims[2] = {w, h};
|
||||
env->SetIntArrayRegion(dimens, 0, 2, dims);
|
||||
|
||||
return result;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue