- rdsrc 统一文档源抽象:TXT/FB2/EPUB/MOBI/CBZ 都产出「UTF-8 段序列+目录+元数据+图片」, 与 R1 rdtxt 段契约一致;book.c 改喂 rd_src(文本)或图页(CBZ)。 - EPUB:miniz 解 ZIP → 自写 rdxml 回调解析 OPF(spine/manifest)+NCX/nav → 正文 XHTML 用 rdhtml 逐行粗解析(坏标签/未闭合/实体容错,不建 DOM),章节按 RDSRC_SEG_MAX 分片。 - FB2:rdxml 严格解析抽 section 段落 + base64 内嵌图;段题进正文+目录。 - MOBI/AZW3:vendor libmobi 最小调用面(mobi_init→load→parse_kf7/8→parse_rawml_opt→ flow/resources),HTML 走 rdhtml 同款粗解析;LGPL-3.0 合规见 NOTICE(版权+全文+锁定 commit)。 - CBZ:miniz 解 ZIP → 自然序图片序列,rdimg(stb_image) 解码+降采样,阅读页图页模式。 - 目录显示与跳转(EPUB NCX/FB2 section/MOBI 标题);书架开放四格式;进度按 (段,字符偏移)(TXT/FB2/EPUB/MOBI)/页号(CBZ)。 - 宿主单测 loaders_smoke(四格式抽取/目录/图片/base64/页序)+ qemu-mipsel formats_smoke/book_smoke;R1 test_reader_core 58/0 不回归。 - build_reader.sh 集成 miniz/libmobi/stb/zlib 头;NOTICE 入仓;交叉 -Wall -Wextra 0 warning。 新 reader md5: e29036599300eb277b1c960a75b65dbf
75 lines
2.8 KiB
C
75 lines
2.8 KiB
C
/* rdimg.c — stb_image 封装(实现见 rdimg.h)。 */
|
|
#include "rdimg.h"
|
|
#include "stb_image.h"
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
int rdimg_probe_wh(const uint8_t *data, size_t size, int *w, int *h)
|
|
{
|
|
if (!data || !w || !h) return -1;
|
|
int x = 0, y = 0, c = 0;
|
|
if (!stbi_info_from_memory(data, (int)size, &x, &y, &c)) return -1;
|
|
*w = x; *h = y;
|
|
return 0;
|
|
}
|
|
|
|
/* 双线性采样单通道:src 步长 sw,取 (fx,fy) 浮点邻近 4 像素加权。 */
|
|
static int bilin(const uint8_t *s, int sw, int sh, double fx, double fy, int ch)
|
|
{
|
|
int x0 = (int)fx, y0 = (int)fy;
|
|
double dx = fx - x0, dy = fy - y0;
|
|
int x1 = x0 + 1 < sw ? x0 + 1 : x0;
|
|
int y1 = y0 + 1 < sh ? y0 + 1 : y0;
|
|
double top = s[y0 * sw * ch + x0 * ch] * (1 - dx) + s[y0 * sw * ch + x1 * ch] * dx;
|
|
double bot = s[y1 * sw * ch + x0 * ch] * (1 - dx) + s[y1 * sw * ch + x1 * ch] * dx;
|
|
return (int)(top * (1 - dy) + bot * dy);
|
|
}
|
|
|
|
int rdimg_decode_scale(const uint8_t *data, size_t size, int max_w, int max_h,
|
|
uint16_t **out565, int *ow, int *oh)
|
|
{
|
|
if (!data || !out565) return -1;
|
|
*out565 = NULL; *ow = *oh = 0;
|
|
int w = 0, h = 0, ch = 0;
|
|
/* 请求 RGB(3 通道)便于统一处理 */
|
|
stbi_uc *px = stbi_load_from_memory(data, (int)size, &w, &h, &ch, 3);
|
|
if (!px || w <= 0 || h <= 0) return -1;
|
|
|
|
/* 缩放:长边超 max 才缩(不放大) */
|
|
double scale = 1.0;
|
|
if (w > max_w && max_w > 0) scale = (double)max_w / w;
|
|
if (h > max_h && max_h > 0) { double s2 = (double)max_h / h; if (s2 < scale) scale = s2; }
|
|
int dw = (int)(w * scale), dh = (int)(h * scale);
|
|
if (dw < 1) dw = 1;
|
|
if (dh < 1) dh = 1;
|
|
|
|
uint16_t *dst = (uint16_t *)malloc((size_t)dw * (size_t)dh * 2);
|
|
if (!dst) { stbi_image_free(px); return -6; }
|
|
if (scale == 1.0) {
|
|
/* 原尺寸直接转 565 */
|
|
for (int yy = 0; yy < dh; yy++) {
|
|
const stbi_uc *s = px + (size_t)yy * w * 3;
|
|
uint16_t *d = dst + (size_t)yy * dw;
|
|
for (int xx = 0; xx < dw; xx++) {
|
|
int r = s[xx*3], g = s[xx*3+1], b = s[xx*3+2];
|
|
d[xx] = (uint16_t)(((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3));
|
|
}
|
|
}
|
|
} else {
|
|
for (int yy = 0; yy < dh; yy++) {
|
|
double fy = (double)yy / scale;
|
|
uint16_t *d = dst + (size_t)yy * dw;
|
|
for (int xx = 0; xx < dw; xx++) {
|
|
double fx = (double)xx / scale;
|
|
int r = bilin(px, w, h, fx, fy, 3);
|
|
int g = bilin((const uint8_t*)px + 1, w, h, fx, fy, 3);
|
|
int b = bilin((const uint8_t*)px + 2, w, h, fx, fy, 3);
|
|
d[xx] = (uint16_t)(((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3));
|
|
}
|
|
}
|
|
}
|
|
stbi_image_free(px);
|
|
*out565 = dst; *ow = dw; *oh = dh;
|
|
return 0;
|
|
}
|