Compare commits
No commits in common. "2bd77e8121cdd03f7c039b487fd6803a947eea69" and "22cad985003c9bd269b291910564551e4caadcab" have entirely different histories.
2bd77e8121
...
22cad98500
18
README.md
18
README.md
@ -58,11 +58,6 @@ see [Screen capture](#screen-capture).
|
||||
move the file to the Recycle Bin or to delete it permanently, overwriting it with random bytes
|
||||
first; "Don't ask again" keeps the choice until the app restarts. Only the `.mcap` goes: the
|
||||
`.snagx` it was converted from is untouched.
|
||||
- **Copy:** click a thumbnail to select it (it is outlined, and shown in the Capture window), then
|
||||
**Ctrl-C** copies its image, as the Capture window shows it (annotations and all; a video's
|
||||
frame), and **Ctrl-Shift-C** its full path. Neither acts while you type in the search box. They
|
||||
are `copy_image` and `copy_path` in `[hotkeys]` in `settings.config`. Copying images is Windows
|
||||
only so far.
|
||||
- **Files added or deleted outside the app** (in Explorer, by another program) appear in the grid
|
||||
or leave it on their own, folders added, renamed or deleted too: the library is watched.
|
||||
**Refresh** looks at the whole folder again, should the watcher have missed something.
|
||||
@ -98,18 +93,7 @@ grid (in its order, so through a search's matches).
|
||||
### The OCR window
|
||||
|
||||
- **Model:** PP-OCRv5 mobile (light, about 85 ms a capture on the GPU) or server (more accurate,
|
||||
about 0.3 s when it runs well; see below). The choice is kept in the settings file (`model` under
|
||||
`[ocr]`).
|
||||
- **Known issue, the server model on the GPU:** its speed is bimodal. The same program on the same
|
||||
20 captures (RTX 5080 laptop, 16 GB) runs either at about 0.27 s a capture with a peak of about
|
||||
2.4 GB of process memory, or at about 1.5 s with about 6.6 GB, with no change between runs and
|
||||
15 GB of the GPU's memory free beforehand. Longer runs fare worse: 50 captures peaked at 16 GB, and
|
||||
100 averaged about 4.6 s a capture. The extra memory looks like GPU allocations spilling into shared
|
||||
system memory, which Windows then pages: what the GPU memory defaults (onnxruntime's
|
||||
kNextPowerOfTwo arena, no cuDNN max workspace, 4 workers) were meant to stop, and which they
|
||||
only partly did. It is the same with Jai's allocator and with rpmalloc. Until it is fixed, scan a
|
||||
large library with the mobile model. Measured on 2026-10-13 with
|
||||
`ocr-bench -models ppocr-v5-server -gpu-only -limit 20`.
|
||||
about 0.4 s). The choice is kept in the settings file (`model` under `[ocr]`).
|
||||
- **Running on:** the GPU or the CPU, and if the CPU, what to install for the GPU.
|
||||
- **Scan the library** reads every capture the model has not read yet and, with **Labels too**,
|
||||
labels every capture not yet labelled with the current list. While a search is active the button
|
||||
|
||||
@ -18,10 +18,6 @@ Ctrl-Equal increase_font_size
|
||||
Ctrl-Alt-Space reset_window
|
||||
Ctrl-Shift-Alt-R reset_layout
|
||||
|
||||
# Library: the selected capture
|
||||
Ctrl-C copy_image
|
||||
Ctrl-Shift-C copy_path
|
||||
|
||||
# Debug
|
||||
Ctrl-Shift-D toggle_debug_panel
|
||||
Ctrl-Shift-L toggle_logger_panel
|
||||
|
||||
@ -18,10 +18,6 @@ Cmd-Equal increase_font_size
|
||||
Cmd-Opt-Shift-Space reset_window
|
||||
Cmd-Shift-Opt-R reset_layout
|
||||
|
||||
# Library: the selected capture
|
||||
Cmd-C copy_image
|
||||
Cmd-Shift-C copy_path
|
||||
|
||||
# Debug
|
||||
Cmd-Shift-D toggle_debug_panel
|
||||
Cmd-Shift-L toggle_logger_panel
|
||||
|
||||
@ -47,7 +47,7 @@ APP_NAME :: "mcap";
|
||||
APP_FOLDER_NAME :: "mcap";
|
||||
GIT_BRANCH :: "check";
|
||||
GIT_HASH :: "-";
|
||||
VERSION :: "0.1.16";
|
||||
VERSION :: "0.1.15";
|
||||
BUILD_DATE :: "-";
|
||||
DEBUG :: true;
|
||||
COMPILE_TESTS :: true;
|
||||
|
||||
@ -8,7 +8,7 @@ APP_NAME :: "mcap";
|
||||
APP_FOLDER_NAME :: "mcap";
|
||||
APP_BUNDLE_IDENTIFIER :: "com.example.mcap";
|
||||
|
||||
VERSION :: "0.1.16";
|
||||
VERSION :: "0.1.15";
|
||||
// Where everything goes: bin/, or bin-headless/ for builds made with no_crash_dialog, so automated
|
||||
// builds never write over the ones you run by hand.
|
||||
build_directory := "bin";
|
||||
|
||||
@ -156,14 +156,6 @@ viewer: struct {
|
||||
open_name: string;
|
||||
open_result: string; // the file written, or ""; heap, the open thread's until it ends
|
||||
open_error: string;
|
||||
|
||||
// The selected capture's image, decoded off the main thread for the clipboard (viewer_copy_image).
|
||||
copy_thread: Thread;
|
||||
copy_started: bool;
|
||||
copy_busy: bool; // set by the main thread, cleared by the copy thread when it ends
|
||||
copy_source: string; // the .mcap; heap, main thread's until the thread starts
|
||||
copy_name: string;
|
||||
copy_done: Decoded; // the copy thread's until it ends
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- startup and shutdown
|
||||
@ -237,7 +229,6 @@ viewer_shutdown :: () {
|
||||
for 1..viewer.workers_started signal(*viewer.wake);
|
||||
for 0..viewer.workers_started - 1 thread_is_done(*viewer.workers[it], -1);
|
||||
if viewer.open_started thread_is_done(*viewer.open_thread, -1);
|
||||
if viewer.copy_started thread_is_done(*viewer.copy_thread, -1);
|
||||
background_shutdown();
|
||||
catalog_cache_save_at_shutdown(); // the workers have stopped: nothing changes the entries now
|
||||
viewer_watch_stop();
|
||||
@ -460,7 +451,6 @@ viewer_frame_gpu_work :: () {
|
||||
viewer_apply_catalog_updates();
|
||||
catalog_cache_frame(); // saves the catalog cache once it is complete and has changed (app/catalog.jai)
|
||||
viewer_open_frame();
|
||||
viewer_copy_frame();
|
||||
segment_overlay_frame(); // the Capture window's segments: what arrived, and its texture (app/segment_ui.jai)
|
||||
background_frame(); // takes back search results, and starts a search when visible_dirty (app/background.jai)
|
||||
}
|
||||
@ -1225,77 +1215,6 @@ viewer_open_frame :: () {
|
||||
else toast_show(.Error, "Could not write % out: %", viewer.open_name, viewer.open_error);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- copying the selected capture
|
||||
|
||||
// The selected capture: the one outlined in the grid and shown in the Capture window. -1 when none.
|
||||
viewer_selected :: () -> s32 {
|
||||
index := viewer.full_index;
|
||||
if index < 0 || index >= viewer.captures.count || viewer.captures[index].removed return -1;
|
||||
return index;
|
||||
}
|
||||
|
||||
// Ctrl-Shift-C (copy_path in [hotkeys]): the selected capture's path, as the system writes paths.
|
||||
viewer_copy_path :: () {
|
||||
index := viewer_selected();
|
||||
if index < 0 { toast_show(.Error, "Select a capture to copy its path"); return; }
|
||||
capture := *viewer.captures[index];
|
||||
path := capture.path;
|
||||
#if OS == .WINDOWS path = replace(path, "/", "\\",, temp);
|
||||
clipboard_set_text(path);
|
||||
toast_show(.Success, "Copied the path of %", capture.name);
|
||||
}
|
||||
|
||||
// Ctrl-C (copy_image in [hotkeys]): the selected capture's image, as the Capture window shows it
|
||||
// (annotations and all; a video's frame), decoded on a thread of its own and put on the clipboard
|
||||
// by viewer_copy_frame.
|
||||
viewer_copy_image :: () {
|
||||
index := viewer_selected();
|
||||
if index < 0 { toast_show(.Error, "Select a capture to copy its image"); return; }
|
||||
capture := *viewer.captures[index];
|
||||
#if OS != .WINDOWS {
|
||||
toast_show(.Error, "Copying images is not available on this system yet");
|
||||
return;
|
||||
}
|
||||
if viewer.copy_started { toast_show(.Error, "Still copying %", viewer.copy_name); return; }
|
||||
push_allocator(context.default_allocator);
|
||||
free(viewer.copy_source); free(viewer.copy_name);
|
||||
viewer.copy_source = copy_string(capture.path);
|
||||
viewer.copy_name = copy_string(capture.name);
|
||||
viewer.copy_done = .{};
|
||||
viewer.copy_busy = true;
|
||||
// Reading an image takes a few MB of temporary storage, as on the viewer's workers.
|
||||
viewer.copy_started = thread_init(*viewer.copy_thread, viewer_copy_proc, temporary_storage_size = 1024 * 1024, name = "copy image");
|
||||
if !viewer.copy_started { viewer.copy_busy = false; toast_show(.Error, "Could not copy %", capture.name); return; }
|
||||
thread_start(*viewer.copy_thread);
|
||||
}
|
||||
|
||||
viewer_copy_proc :: (thread: *Thread) -> s64 {
|
||||
context.allocator = context.default_allocator;
|
||||
defer atomic_swap(*viewer.copy_busy, false);
|
||||
viewer.copy_done = viewer_decode_full(viewer.copy_source);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Each frame: puts what viewer_copy_proc decoded on the clipboard, once it is done.
|
||||
viewer_copy_frame :: () {
|
||||
if !viewer.copy_started || viewer.copy_busy return;
|
||||
thread_is_done(*viewer.copy_thread, -1);
|
||||
thread_deinit(*viewer.copy_thread);
|
||||
viewer.copy_started = false;
|
||||
done := *viewer.copy_done;
|
||||
defer viewer_free_pixels(done);
|
||||
if done.failed { toast_show(.Error, "Could not read the image of %; see the Event Log", viewer.copy_name); return; }
|
||||
pixels := []u8.{cast(s64) done.width * done.height * 4, done.pixels};
|
||||
if !platform_copy_image_to_clipboard(pixels, done.width, done.height) {
|
||||
log_error("[viewer] Could not put the image of % on the clipboard.", viewer.copy_source);
|
||||
toast_show(.Error, "Could not put % on the clipboard", viewer.copy_name);
|
||||
return;
|
||||
}
|
||||
scaled := ifx done.width != done.source_width || done.height != done.source_height then tprint(", scaled down from % x %", done.source_width, done.source_height) else "";
|
||||
log("[viewer] Copied the image of % (% x %%).", viewer.copy_source, done.width, done.height, scaled);
|
||||
toast_show(.Success, "Copied % (% x %%)", viewer.copy_name, done.width, done.height, scaled);
|
||||
}
|
||||
|
||||
viewer_grid :: () { using ImGui;
|
||||
style := GetStyle();
|
||||
cell := viewer.thumb_size;
|
||||
|
||||
@ -148,9 +148,8 @@ to_string_all_bindings :: (hotkey: Hotkey) -> string {
|
||||
// The bindings are read from settings.config, or from DEFAULT_HOTKEYS_DATA when the file has
|
||||
// no [hotkeys] section; see hotkeys_install. once and ignore_when_text_field_active belong to the
|
||||
// action and are set here. To add an action: declare its Hotkey here, add it to
|
||||
// hotkey_actions_build and app_check_key_combinations, and bind it in both
|
||||
// assets/data/default_hotkeys files. Settings files at APP_USER_SETTINGS_VERSION get its default
|
||||
// binding at the next start (hotkeys_missing_lines); raising the version would give them "none".
|
||||
// hotkey_actions_build and app_check_key_combinations, bind it in both assets/data/default_hotkeys
|
||||
// files, and raise APP_USER_SETTINGS_VERSION so existing settings files get its default.
|
||||
program_exit_hotkey: Hotkey;
|
||||
minimize_to_tray_hotkey: Hotkey;
|
||||
toggle_debug_panel_hotkey: Hotkey;
|
||||
@ -163,10 +162,6 @@ increase_font_size_hotkey: Hotkey;
|
||||
reset_window_hotkey: Hotkey;
|
||||
reset_layout_hotkey: Hotkey;
|
||||
|
||||
// The selected capture (app/viewer.jai). Not while typing, so Ctrl-C in the search box copies its text.
|
||||
copy_image_hotkey: Hotkey = .{ignore_when_text_field_active = true};
|
||||
copy_path_hotkey: Hotkey = .{ignore_when_text_field_active = true};
|
||||
|
||||
Hotkey_Action :: struct {
|
||||
name: string; // as written in [hotkeys]
|
||||
hotkey: *Hotkey;
|
||||
@ -187,8 +182,6 @@ hotkey_actions_build :: (out: *[..] Hotkey_Action) {
|
||||
add(out, "increase_font_size", *increase_font_size_hotkey);
|
||||
add(out, "reset_window", *reset_window_hotkey);
|
||||
add(out, "reset_layout", *reset_layout_hotkey);
|
||||
add(out, "copy_image", *copy_image_hotkey);
|
||||
add(out, "copy_path", *copy_path_hotkey);
|
||||
}
|
||||
|
||||
hotkey_actions: [..] Hotkey_Action;
|
||||
@ -634,9 +627,6 @@ app_check_key_combinations :: () {
|
||||
else toast_show(.Error, "Could not reset the window");
|
||||
}
|
||||
if check_key_combination(*reset_layout_hotkey) imgui_reset_layout_requested = true; // applied between frames
|
||||
// The viewer is the shutdown thread's once shutdown has started.
|
||||
if check_key_combination(*copy_image_hotkey) && !app_exit_shutdown_started() viewer_copy_image();
|
||||
if check_key_combination(*copy_path_hotkey) && !app_exit_shutdown_started() viewer_copy_path();
|
||||
|
||||
if should_exit_this_frame {
|
||||
log("Calling exit hotkey... exiting program!");
|
||||
|
||||
Loading…
Reference in New Issue
Block a user