/* logic/reader/page_source.h — 页源契约(纯 C,不依赖 meow_ui.h)。 * * 一册 = 有序页序列。契约只有四件事: * count 总页数 * meta(i) 页的原始像素尺寸(可选;条漫连续滚动先用它排版,未知时返回 0) * open(i) 取第 i 页:解码 + downscale 后返回 meow_img*(调用方拥有,必须 close) * close(img) 释放 open 返回的图像 * * 两种消费方式共用同一契约,后续实现零改动: * - 左右翻页(本任务):预解码窗口 = 当前 ±1 页,翻页只 blit 窗口内已备好的图; * - 条漫连续滚动(M7):先 meta(i) 累加高度排版,再按滚动位置 open(视口±1 页)。 * zip 册(M9/M11)只需另写一套 mr_book_ops,目录册是第一个实现。 * * meow_img 在 logic 层是前向声明的不透明句柄;解码/释放由 UI 层注入回调 * (logic 不 include SDK,宿主测试用假回调即可覆盖契约边界)。 */ #ifndef MR_PAGE_SOURCE_H #define MR_PAGE_SOURCE_H #include "logic/library.h" /* mr_path_is_image / mr_natural_cmp / MR_PATH_MAX / MR_NAME_MAX */ #ifdef __cplusplus extern "C" { #endif struct meow_img; typedef struct meow_img meow_img; /* SDK 不透明句柄;logic 层只透传 */ #define MR_BOOK_MAX_PAGES 4096 /* 单册页数上限(防坏卡/巨目录撑爆内存) */ /* 解码回调(UI 层注入):解码 path,长边 >maxdim 时等比 downscale;失败返回 NULL。 * 必须可在后台线程调用(宿主测试用假实现)。 */ typedef meow_img *(*mr_book_load_fn)(const char *path, void *ud, int maxdim); /* 释放 open 返回的图像(UI 层注入 meow_img_free;宿主测试用假实现计数)。 */ typedef void (*mr_book_unload_fn)(meow_img *img); typedef struct mr_book_ops { int (*count)(void *ctx); /* 页原始尺寸(未 downscale);1=已知,0=未知。可为 NULL。 */ int (*meta)(void *ctx, int index, int *w, int *h); /* 取页:越界/解码失败返回 NULL。返回值的所有权交给调用方。 */ meow_img *(*open)(void *ctx, int index); /* 释放 open 返回的图像;须容忍 NULL。 */ void (*close)(void *ctx, meow_img *img); /* 释放 provider 自身(册内索引等)。可为 NULL。 */ void (*destroy)(void *ctx); } mr_book_ops; typedef struct mr_book { const mr_book_ops *ops; void *ctx; } mr_book; /* ---- 契约包装:所有入口对 NULL/越界安全(越界 open 返回 NULL) ---- */ int mr_book_valid(const mr_book *b); int mr_book_count(const mr_book *b); int mr_book_meta(const mr_book *b, int index, int *w, int *h); meow_img *mr_book_open(mr_book *b, int index); void mr_book_close(mr_book *b, meow_img *img); /* 释放 provider 自身(不含已 open 的图像——那些由调用方先 close)。幂等。 */ void mr_book_destroy(mr_book *b); /* ---- 目录册(文件夹即书):目录直接子文件里的图片按自然序成册 ---- */ typedef struct mr_dir_book { char dir[MR_PATH_MAX]; char **names; /* 自然序文件名(堆分配) */ int count; int maxdim; /* open 时传给解码回调的长边上限 */ mr_book_load_fn load; mr_book_unload_fn unload; void *ud; /* 解码回调的宿主上下文 */ } mr_dir_book; /* 扫描 dir 的直接子文件,收图片名并自然排序。 * 返回页数(>=0);参数非法 / 目录不可读 / 内存不足返回 -1(db 已清空、可安全 free)。 */ int mr_dir_book_init(mr_dir_book *db, const char *dir, int maxdim, mr_book_load_fn load, mr_book_unload_fn unload, void *ud); void mr_dir_book_free(mr_dir_book *db); /* 第 index 页的完整路径;越界时输出空串。 */ void mr_dir_book_path(const mr_dir_book *db, int index, char *out, int outsz); /* 把目录册绑定到通用 mr_book(db 生命周期由调用方持有)。 */ void mr_dir_book_bind(mr_book *b, mr_dir_book *db); /* 纯 C 头解析:取图片原始像素尺寸(不解码像素)。 * PNG(IHDR)/ JPEG(SOF0-15)/ BMP(BITMAPINFOHEADER+)。1=已知,0=未知。 */ int mr_probe_size(const char *path, int *w, int *h); #ifdef __cplusplus } #endif #endif /* MR_PAGE_SOURCE_H */