static inline void jxr_unpack_alpha_sample(fz_context *ctx, struct info *info, jxr_image_t image, int *sp, unsigned char *dp) { int bpc = jxr_get_CONTAINER_BPC(image); switch (bpc) { default: fz_throw(ctx, FZ_ERROR_GENERIC, "unknown alpha sample type: %d", bpc); case JXR_BD8: dp[0] = sp[0]; break; case JXR_BD10: dp[0] = sp[0] >> 2; break; case JXR_BD16: dp[0] = sp[0] >> 8; break; case JXR_BD16S: dp[0] = fz_clamp(sp[0] * (1.0f / (1 << 13)), 0, 1) * 255 + 0.5f; break; case JXR_BD32S: dp[0] = fz_clamp(sp[0] * (1.0f / (1 << 24)), 0, 1) * 255 + 0.5f; break; case JXR_BD16F: dp[0] = fz_clamp(float32_from_float16(sp[0]), 0, 1) * 255 + 0.5f; break; case JXR_BD32F: dp[0] = fz_clamp(float32_from_int32_bits(sp[0]), 0, 1) * 255 + 0.5f; break; } }
static inline void jxr_unpack_sample(fz_context *ctx, struct info *info, jxr_image_t image, int *sp, unsigned char *dp) { int k, bpc, comps, alpha; float v; if (info->format == JXRC_FMT_32bppRGBE) { dp[0] = sRGB_from_scRGB(ldexpf(sp[0], sp[3] - 128 - 8)) * 255 + 0.5f; dp[1] = sRGB_from_scRGB(ldexpf(sp[1], sp[3] - 128 - 8)) * 255 + 0.5f; dp[2] = sRGB_from_scRGB(ldexpf(sp[2], sp[3] - 128 - 8)) * 255 + 0.5f; return; } if (info->format == JXRC_FMT_16bppBGR565) { dp[0] = sp[0] << 3; dp[1] = sp[1] << 2; dp[2] = sp[2] << 3; return; } comps = fz_mini(fz_colorspace_n(ctx, info->cspace), jxr_get_IMAGE_CHANNELS(image)); alpha = jxr_get_ALPHACHANNEL_FLAG(image); bpc = jxr_get_CONTAINER_BPC(image); for (k = 0; k < comps + alpha; k++) { switch (bpc) { default: fz_throw(ctx, FZ_ERROR_GENERIC, "unknown sample type: %d", bpc); case JXR_BD1WHITE1: dp[k] = sp[k] ? 255 : 0; break; case JXR_BD1BLACK1: dp[k] = sp[k] ? 0 : 255; break; case JXR_BD5: dp[k] = sp[k] << 3; break; case JXR_BD8: dp[k] = sp[k]; break; case JXR_BD10: dp[k] = sp[k] >> 2; break; case JXR_BD16: dp[k] = sp[k] >> 8; break; case JXR_BD16S: v = sp[k] * (1.0f / (1 << 13)); goto decode_float32; case JXR_BD32S: v = sp[k] * (1.0f / (1 << 24)); goto decode_float32; case JXR_BD16F: v = float32_from_float16(sp[k]); goto decode_float32; case JXR_BD32F: v = float32_from_int32_bits(sp[k]); goto decode_float32; decode_float32: if (k < comps) dp[k] = sRGB_from_scRGB(fz_clamp(v, 0, 1)) * 255 + 0.5f; else dp[k] = fz_clamp(v, 0, 1) * 255 + 0.5f; break; } } }
static void lab_to_rgb(fz_context *ctx, fz_colorspace *cs, float *lab, float *rgb) { /* input is in range (0..100, -128..127, -128..127) not (0..1, 0..1, 0..1) */ float lstar, astar, bstar, l, m, n, x, y, z, r, g, b; lstar = lab[0]; astar = lab[1]; bstar = lab[2]; m = (lstar + 16) / 116; l = m + astar / 500; n = m - bstar / 200; x = fung(l); y = fung(m); z = fung(n); r = (3.240449f * x + -1.537136f * y + -0.498531f * z) * 0.830026f; g = (-0.969265f * x + 1.876011f * y + 0.041556f * z) * 1.05452f; b = (0.055643f * x + -0.204026f * y + 1.057229f * z) * 1.1003f; rgb[0] = sqrtf(fz_clamp(r, 0, 1)); rgb[1] = sqrtf(fz_clamp(g, 0, 1)); rgb[2] = sqrtf(fz_clamp(b, 0, 1)); }
void fz_insert_gel_rect(fz_context *ctx, fz_gel *gel, float fx0, float fy0, float fx1, float fy1) { int x0, y0, x1, y1; const int hscale = fz_aa_hscale; const int vscale = fz_aa_vscale; if (fx0 <= fx1) { fx0 = floorf(fx0 * hscale); fx1 = ceilf(fx1 * hscale); } else { fx0 = ceilf(fx0 * hscale); fx1 = floorf(fx1 * hscale); } if (fy0 <= fy1) { fy0 = floorf(fy0 * vscale); fy1 = ceilf(fy1 * vscale); } else { fy0 = ceilf(fy0 * vscale); fy1 = floorf(fy1 * vscale); } fx0 = fz_clamp(fx0, gel->clip.x0, gel->clip.x1); fx1 = fz_clamp(fx1, gel->clip.x0, gel->clip.x1); fy0 = fz_clamp(fy0, gel->clip.y0, gel->clip.y1); fy1 = fz_clamp(fy1, gel->clip.y0, gel->clip.y1); /* Call fz_clamp so that clamping is done in the float domain, THEN * cast down to an int. Calling fz_clampi causes problems due to the * implicit cast down from float to int of the first argument * over/underflowing and flipping sign at extreme values. */ x0 = (int)fz_clamp(fx0, BBOX_MIN * hscale, BBOX_MAX * hscale); y0 = (int)fz_clamp(fy0, BBOX_MIN * vscale, BBOX_MAX * vscale); x1 = (int)fz_clamp(fx1, BBOX_MIN * hscale, BBOX_MAX * hscale); y1 = (int)fz_clamp(fy1, BBOX_MIN * vscale, BBOX_MAX * vscale); fz_insert_gel_raw(ctx, gel, x1, y0, x1, y1); fz_insert_gel_raw(ctx, gel, x0, y1, x0, y0); }
static void fz_std_conv_color(fz_context *ctx, fz_colorspace *srcs, float *srcv, fz_colorspace *dsts, float *dstv) { float rgb[3]; int i; if (srcs != dsts) { assert(srcs->to_rgb && dsts->from_rgb); srcs->to_rgb(ctx, srcs, srcv, rgb); dsts->from_rgb(ctx, dsts, rgb, dstv); for (i = 0; i < dsts->n; i++) dstv[i] = fz_clamp(dstv[i], 0, 1); } else { for (i = 0; i < srcs->n; i++) dstv[i] = srcv[i]; } }
static void cmyk_to_rgb(fz_context *ctx, fz_colorspace *cs, const float *cmyk, float *rgb) { #ifdef SLOWCMYK /* from poppler */ float c = cmyk[0], m = cmyk[1], y = cmyk[2], k = cmyk[3]; float r, g, b, x; float cm = c * m; float c1m = m - cm; float cm1 = c - cm; float c1m1 = 1 - m - cm1; float c1m1y = c1m1 * y; float c1m1y1 = c1m1 - c1m1y; float c1my = c1m * y; float c1my1 = c1m - c1my; float cm1y = cm1 * y; float cm1y1 = cm1 - cm1y; float cmy = cm * y; float cmy1 = cm - cmy; /* this is a matrix multiplication, unrolled for performance */ x = c1m1y1 * k; /* 0 0 0 1 */ r = g = b = c1m1y1 - x; /* 0 0 0 0 */ r += 0.1373 * x; g += 0.1216 * x; b += 0.1255 * x; x = c1m1y * k; /* 0 0 1 1 */ r += 0.1098 * x; g += 0.1020 * x; x = c1m1y - x; /* 0 0 1 0 */ r += x; g += 0.9490 * x; x = c1my1 * k; /* 0 1 0 1 */ r += 0.1412 * x; x = c1my1 - x; /* 0 1 0 0 */ r += 0.9255 * x; b += 0.5490 * x; x = c1my * k; /* 0 1 1 1 */ r += 0.1333 * x; x = c1my - x; /* 0 1 1 0 */ r += 0.9294 * x; g += 0.1098 * x; b += 0.1412 * x; x = cm1y1 * k; /* 1 0 0 1 */ g += 0.0588 * x; b += 0.1412 * x; x = cm1y1 - x; /* 1 0 0 0 */ g += 0.6784 * x; b += 0.9373 * x; x = cm1y * k; /* 1 0 1 1 */ g += 0.0745 * x; x = cm1y - x; /* 1 0 1 0 */ g += 0.6510 * x; b += 0.3137 * x; x = cmy1 * k; /* 1 1 0 1 */ b += 0.0078 * x; x = cmy1 - x; /* 1 1 0 0 */ r += 0.1804 * x; g += 0.1922 * x; b += 0.5725 * x; x = cmy * (1-k); /* 1 1 1 0 */ r += 0.2118 * x; g += 0.2119 * x; b += 0.2235 * x; rgb[0] = fz_clamp(r, 0, 1); rgb[1] = fz_clamp(g, 0, 1); rgb[2] = fz_clamp(b, 0, 1); #else rgb[0] = 1 - fz_min(1, cmyk[0] + cmyk[3]); rgb[1] = 1 - fz_min(1, cmyk[1] + cmyk[3]); rgb[2] = 1 - fz_min(1, cmyk[2] + cmyk[3]); #endif }
void fz_insert_gel(fz_context *ctx, fz_gel *gel, float fx0, float fy0, float fx1, float fy1) { int x0, y0, x1, y1; int d, v; const int hscale = fz_aa_hscale; const int vscale = fz_aa_vscale; fx0 = floorf(fx0 * hscale); fx1 = floorf(fx1 * hscale); fy0 = floorf(fy0 * vscale); fy1 = floorf(fy1 * vscale); /* Call fz_clamp so that clamping is done in the float domain, THEN * cast down to an int. Calling fz_clampi causes problems due to the * implicit cast down from float to int of the first argument * over/underflowing and flipping sign at extreme values. */ x0 = (int)fz_clamp(fx0, BBOX_MIN * hscale, BBOX_MAX * hscale); y0 = (int)fz_clamp(fy0, BBOX_MIN * vscale, BBOX_MAX * vscale); x1 = (int)fz_clamp(fx1, BBOX_MIN * hscale, BBOX_MAX * hscale); y1 = (int)fz_clamp(fy1, BBOX_MIN * vscale, BBOX_MAX * vscale); d = clip_lerp_y(gel->clip.y0, 0, x0, y0, x1, y1, &v); if (d == OUTSIDE) return; if (d == LEAVE) { y1 = gel->clip.y0; x1 = v; } if (d == ENTER) { y0 = gel->clip.y0; x0 = v; } d = clip_lerp_y(gel->clip.y1, 1, x0, y0, x1, y1, &v); if (d == OUTSIDE) return; if (d == LEAVE) { y1 = gel->clip.y1; x1 = v; } if (d == ENTER) { y0 = gel->clip.y1; x0 = v; } d = clip_lerp_x(gel->clip.x0, 0, x0, y0, x1, y1, &v); if (d == OUTSIDE) { x0 = x1 = gel->clip.x0; } if (d == LEAVE) { fz_insert_gel_raw(ctx, gel, gel->clip.x0, v, gel->clip.x0, y1); x1 = gel->clip.x0; y1 = v; } if (d == ENTER) { fz_insert_gel_raw(ctx, gel, gel->clip.x0, y0, gel->clip.x0, v); x0 = gel->clip.x0; y0 = v; } d = clip_lerp_x(gel->clip.x1, 1, x0, y0, x1, y1, &v); if (d == OUTSIDE) { x0 = x1 = gel->clip.x1; } if (d == LEAVE) { fz_insert_gel_raw(ctx, gel, gel->clip.x1, v, gel->clip.x1, y1); x1 = gel->clip.x1; y1 = v; } if (d == ENTER) { fz_insert_gel_raw(ctx, gel, gel->clip.x1, y0, gel->clip.x1, v); x0 = gel->clip.x1; y0 = v; } fz_insert_gel_raw(ctx, gel, x0, y0, x1, y1); }
static void do_app(void) { if (ui.key == KEY_F4 && ui.mod == GLFW_MOD_ALT) quit(); if (ui.down || ui.middle || ui.right || ui.key) showinfo = 0; if (!ui.focus && ui.key) { switch (ui.key) { case 'q': quit(); break; case 'm': if (number == 0) push_history(); else if (number > 0 && number < nelem(marks)) marks[number] = currentpage; break; case 't': if (number == 0) { if (history_count > 0) pop_history(); } else if (number > 0 && number < nelem(marks)) { jump_to_page(marks[number]); } break; case 'T': if (number == 0) { if (future_count > 0) pop_future(); } break; case 'N': search_dir = -1; if (search_hit_page == currentpage) search_page = currentpage + search_dir; else search_page = currentpage; if (search_page >= 0 && search_page < fz_count_pages(ctx, doc)) { search_hit_page = -1; if (search_needle) search_active = 1; } break; case 'n': search_dir = 1; if (search_hit_page == currentpage) search_page = currentpage + search_dir; else search_page = currentpage; if (search_page >= 0 && search_page < fz_count_pages(ctx, doc)) { search_hit_page = -1; if (search_needle) search_active = 1; } break; case 'f': toggle_fullscreen(); break; case 'w': shrinkwrap(); break; case 'r': reload(); break; case 'o': toggle_outline(); break; case 'W': auto_zoom_w(); break; case 'H': auto_zoom_h(); break; case 'Z': auto_zoom(); break; case 'z': currentzoom = number > 0 ? number : DEFRES; break; case '<': currentpage -= 10 * fz_maxi(number, 1); break; case '>': currentpage += 10 * fz_maxi(number, 1); break; case ',': case KEY_PAGE_UP: currentpage -= fz_maxi(number, 1); break; case '.': case KEY_PAGE_DOWN: currentpage += fz_maxi(number, 1); break; case 'b': number = fz_maxi(number, 1); while (number--) smart_move_backward(); break; case ' ': number = fz_maxi(number, 1); while (number--) smart_move_forward(); break; case 'g': jump_to_page(number - 1); break; case 'G': jump_to_page(fz_count_pages(ctx, doc) - 1); break; case '+': currentzoom = zoom_in(currentzoom); break; case '-': currentzoom = zoom_out(currentzoom); break; case '[': currentrotate += 90; break; case ']': currentrotate -= 90; break; case 'l': showlinks = !showlinks; break; case 'i': showinfo = !showinfo; break; case '/': search_dir = 1; showsearch = 1; search_input.p = search_input.text; search_input.q = search_input.end; break; case '?': search_dir = -1; showsearch = 1; search_input.p = search_input.text; search_input.q = search_input.end; break; case KEY_UP: scroll_y -= 10; break; case KEY_DOWN: scroll_y += 10; break; case KEY_LEFT: scroll_x -= 10; break; case KEY_RIGHT: scroll_x += 10; break; } if (ui.key >= '0' && ui.key <= '9') number = number * 10 + ui.key - '0'; else number = 0; currentpage = fz_clampi(currentpage, 0, fz_count_pages(ctx, doc) - 1); currentzoom = fz_clamp(currentzoom, MINRES, MAXRES); while (currentrotate < 0) currentrotate += 360; while (currentrotate >= 360) currentrotate -= 360; if (search_hit_page != currentpage) search_hit_page = -1; /* clear highlights when navigating */ ui_needs_update = 1; ui.key = 0; /* we ate the key event, so zap it */ } }
static void auto_zoom_h(void) { currentzoom = fz_clamp(currentzoom * canvas_h / (float)page_tex.h, MINRES, MAXRES); }
static void do_canvas(void) { static int saved_scroll_x = 0; static int saved_scroll_y = 0; static int saved_ui_x = 0; static int saved_ui_y = 0; float x, y; if (oldpage != currentpage || oldzoom != currentzoom || oldrotate != currentrotate) { render_page(); update_title(); oldpage = currentpage; oldzoom = currentzoom; oldrotate = currentrotate; } if (ui.x >= canvas_x && ui.x < canvas_x + canvas_w && ui.y >= canvas_y && ui.y < canvas_y + canvas_h) { ui.hot = doc; if (!ui.active && ui.middle) { ui.active = doc; saved_scroll_x = scroll_x; saved_scroll_y = scroll_y; saved_ui_x = ui.x; saved_ui_y = ui.y; } } if (ui.hot == doc) { scroll_x -= ui.scroll_x * ui.lineheight * 3; scroll_y -= ui.scroll_y * ui.lineheight * 3; } if (ui.active == doc) { scroll_x = saved_scroll_x + saved_ui_x - ui.x; scroll_y = saved_scroll_y + saved_ui_y - ui.y; } if (page_tex.w <= canvas_w) { scroll_x = 0; x = canvas_x + (canvas_w - page_tex.w) / 2; } else { scroll_x = fz_clamp(scroll_x, 0, page_tex.w - canvas_w); x = canvas_x - scroll_x; } if (page_tex.h <= canvas_h) { scroll_y = 0; y = canvas_y + (canvas_h - page_tex.h) / 2; } else { scroll_y = fz_clamp(scroll_y, 0, page_tex.h - canvas_h); y = canvas_y - scroll_y; } ui_draw_image(&page_tex, x - page_tex.x, y - page_tex.y); do_forms(x, y); if (!search_active) { do_links(links, x, y); do_page_selection(x, y, x+page_tex.w, y+page_tex.h); if (search_hit_page == currentpage && search_hit_count > 0) do_search_hits(x, y); } }