ricklon commited on
Commit
e3d3adf
·
1 Parent(s): 46b7b46

Auto-zoom tall workspace images toward width

Browse files
Files changed (1) hide show
  1. app.py +93 -1
app.py CHANGED
@@ -337,6 +337,98 @@ math[display="block"] { display: block; overflow-x: auto; max-width: 100%; }
337
  });
338
  observer.observe(document.body, { childList: true, subtree: true });
339
  })();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
340
  </script>
341
  """
342
 
@@ -1585,7 +1677,7 @@ with gr.Blocks(**blocks_kwargs) as demo:
1585
  2. Choose **Input Scope**:
1586
  - `Entire Page` for the full page.
1587
  - `Selected Region` for a specific area.
1588
- 2a. Workspace keeps native image resolution for clarity (especially equations); use in-canvas zoom/pan as needed.
1589
  3. For `Selected Region`, use the **Image Workspace**:
1590
  - Recommended: freehand selection (draw/highlight target); app uses an automatic bounding box around your marks.
1591
  - Optional rectangle selection: use the **Crop** tool.
 
337
  });
338
  observer.observe(document.body, { childList: true, subtree: true });
339
  })();
340
+
341
+ (() => {
342
+ if (window.__ocrWorkspaceZoomInit) return;
343
+ window.__ocrWorkspaceZoomInit = true;
344
+
345
+ const stateByRoot = new WeakMap();
346
+ const targetZoomPct = 100;
347
+ const tinyFitThresholdPct = 45;
348
+
349
+ const getState = (root) => {
350
+ let state = stateByRoot.get(root);
351
+ if (!state) {
352
+ state = { busy: false, applied: false, lastSeenZoom: null, lastAutoAt: 0 };
353
+ stateByRoot.set(root, state);
354
+ }
355
+ return state;
356
+ };
357
+
358
+ const parseZoomPct = (root) => {
359
+ const zoomNode = root.querySelector(".zoom-number span[role='button']");
360
+ if (!zoomNode) return null;
361
+ const m = (zoomNode.textContent || "").match(/([0-9]+(?:\\.[0-9]+)?)\\s*%/);
362
+ return m ? parseFloat(m[1]) : null;
363
+ };
364
+
365
+ const getZoomInBtn = (root) =>
366
+ root.querySelector("button[aria-label='Zoom in'], button[title='Zoom in']");
367
+
368
+ const isWorkspaceRoot = (root) =>
369
+ !!root.querySelector(".pixi-target") && !!root.querySelector(".zoom-number");
370
+
371
+ const maybeAutoZoom = (root) => {
372
+ if (!isWorkspaceRoot(root)) return;
373
+
374
+ const state = getState(root);
375
+ const now = Date.now();
376
+ const zoomPct = parseZoomPct(root);
377
+ if (zoomPct == null) return;
378
+
379
+ // A drop from high zoom to low zoom usually means a new image was loaded.
380
+ if (state.lastSeenZoom != null && state.lastSeenZoom > 70 && zoomPct < 35) {
381
+ state.applied = false;
382
+ }
383
+ state.lastSeenZoom = zoomPct;
384
+
385
+ if (state.busy || state.applied) return;
386
+ if (zoomPct > tinyFitThresholdPct) return;
387
+ if (now - state.lastAutoAt < 1200) return;
388
+
389
+ const zoomInBtn = getZoomInBtn(root);
390
+ if (!zoomInBtn) return;
391
+
392
+ state.busy = true;
393
+ state.lastAutoAt = now;
394
+ let steps = 0;
395
+
396
+ const step = () => {
397
+ const current = parseZoomPct(root);
398
+ if (current == null || current >= targetZoomPct || steps >= 20) {
399
+ state.busy = false;
400
+ state.applied = true;
401
+ return;
402
+ }
403
+ zoomInBtn.click();
404
+ steps += 1;
405
+ setTimeout(step, 80);
406
+ };
407
+
408
+ setTimeout(step, 90);
409
+ };
410
+
411
+ const attachRootObserver = (root) => {
412
+ if (root.dataset.ocrZoomObserved === "1") return;
413
+ root.dataset.ocrZoomObserved = "1";
414
+
415
+ const obs = new MutationObserver(() => maybeAutoZoom(root));
416
+ obs.observe(root, { childList: true, subtree: true, characterData: true });
417
+
418
+ setTimeout(() => maybeAutoZoom(root), 200);
419
+ setTimeout(() => maybeAutoZoom(root), 800);
420
+ };
421
+
422
+ const scan = () => {
423
+ document.querySelectorAll("[data-testid='image']").forEach((root) => {
424
+ if (isWorkspaceRoot(root)) attachRootObserver(root);
425
+ });
426
+ };
427
+
428
+ scan();
429
+ const pageObs = new MutationObserver(scan);
430
+ pageObs.observe(document.body, { childList: true, subtree: true });
431
+ })();
432
  </script>
433
  """
434
 
 
1677
  2. Choose **Input Scope**:
1678
  - `Entire Page` for the full page.
1679
  - `Selected Region` for a specific area.
1680
+ 2a. Workspace keeps native image resolution for clarity. For very tall pages, it auto-boosts from tiny fit view toward width-friendly zoom.
1681
  3. For `Selected Region`, use the **Image Workspace**:
1682
  - Recommended: freehand selection (draw/highlight target); app uses an automatic bounding box around your marks.
1683
  - Optional rectangle selection: use the **Crop** tool.