메뉴
HN
Hacker News • 33일 전

OCR It – 복사 불가능한 문서에서 텍스트를 추출하는 크롬 확장 프로그램

IMP
6/10
핵심 요약

텍스트 선택이 막힌 스캔 책, PDF, 슬라이드 등에서 영역을 한 번 지정하면 핫키 한 번으로 OCR을 실행해 전체 문서를 텍스트로 만들어주는 크롬 확장 프로그램입니다. 자동 페이지 넘김까지 지원하며, Tesseract 기반 OCR이 로컬에서만 돌아가 네트워크 요청 없이 프라이버시가 보장됩니다. 결과물을 Claude나 ChatGPT 같은 LLM에 바로 넘겨 요약·검색·질의에 활용할 수 있습니다.

번역된 본문

OCR It

영역을 한 번만 지정하세요. 이후 매 페이지마다 핫키만 누르면 됩니다. 책 전체를 텍스트로 얻을 수 있습니다.

뷰어에 갇힌 페이지네이션 문서 — 스캔된 책, 슬라이드 덱, PDF, 텍스트 선택을 허용하지 않는 리더 — 를 읽기 위한 크롬 확장 프로그램입니다. 캡처 영역을 한 번 드래그로 지정하면, 그 이후 핫키를 누를 때마다 정확히 그 사각형을 스크린샷으로 찍고, OCR을 돌리고, 텍스트를 진행 중인 트랜스크립트에 추가합니다. 아니면 아예 전체 작업을 자동으로 맡길 수도 있습니다: ⌥⇧A를 누르면 캡처하고 페이지를 넘기고를 문서가 끝날 때까지 반복하는 실행이 시작됩니다.

그다음 결과를 원하는 곳에 붙여넣으면 됩니다 — 가장 명백한 대상은 LLM입니다. 선택할 수 없었던 수백 페이지가 이제 Claude나 ChatGPT에 넘겨 요약·검색·질문을 할 수 있는 텍스트 파일이 되었으니까요.

OCR은 번들된 Tesseract 빌드로 로컬에서 실행됩니다. API 키도, 네트워크도 없고, 이미지가 기기를 떠나지 않습니다 — 이 확장은 아웃바운드 요청을 전혀 보내지 않습니다.

설치

  1. 이 저장소를 다운로드하거나 git clone하세요
  2. chrome://extensions 를 열고 개발자 모드를 켜세요
  3. "압축해제된 확장 프로그램 로드" → 폴더를 선택하세요
  4. 확장을 고정하세요 — 툴바 아이콘은 페이지 카운터를 겸합니다

필요한 모든 것이 커밋되어 있습니다. 빌드 단계가 없습니다: npm install은 테스트 실행이나 Tesseract 재벤더링에만 필요합니다. 그다음 chrome://extensions/shortcuts에서 핫키가 제대로 등록됐는지 확인하세요 — 다른 확장이 이미 해당 키를 점유하고 있으면 Chrome은 조용히 비워둡니다.

설치 시 사이트 접근 권한을 요구하지 않습니다. 단일 캡처는 activeTab 위에서 동작하며, 이는 핫키를 누르거나 팝업을 열 때 Chrome이 넘겨줍니다. 페이지 로드보다 오래 지속되는 자동 실행과 크로스 오리진 iframe 내부에서 페이지를 넘기는 두 가지에는 지속적 권한이 필요하며, 필요할 때 팝업이 현재 사이트에 대한 "허용" 버튼을 제공합니다.

⌥⇧S — 영역을 한 번 캡처 ⌥⇧A — 자동 실행 시작/중지 ⌥⇧R — 영역 그리기 또는 다시 그리기

사용법

  1. 영역 지정 ⌥⇧R을 누른 뒤 텍스트 위에 박스를 드래그하세요. 저장 전에 드래그로 옮기거나, 핸들을 당기거나, 방향키로 한 픽셀씩 조정할 수 있습니다(⇧를 누르면 크기 조절). Enter로 확정합니다. 텍스트 여백보다 약간 안쪽으로 그리세요 — 사각형 안의 모든 것이 읽히며, 페이지 번호와 면주( Running Header )도 포함됩니다.

  2. 캡처 페이지마다 ⌥⇧S를 한 번 누릅니다. 스크린샷은 즉시 찍히고 OCR은 백그라운드에서 돌아가므로 페이지 사이에 기다릴이 없습니다 — 캡처는 큐에 쌓이고 배지가 아직 읽고 있는 항목 수를 셉니다.

  3. 아니면 자동으로 페이지 넘김 컨트롤을 설정하고(아래 참고) ⌥⇧A를 누르면 완전히 대신 해줍니다: 캡처, 넘김, 캡처, 넘김… 문서가 끝날 때까지. 페이지에서 Esc를 누르면 중지됩니다.

  4. 내보내기 모든 페이지는 정확히 잘린 내용의 썸네일과 함께 나열되므로, 영역이 어긋난 경우 80페이지 뒤가 아니라 한눈에 알 수 있습니다. 텍스트는 그 자리에서 편집 가능하며, 잘못 읽은 페이지는 개별적으로 다시 실행할 수 있습니다. "모두 복사"와 ".txt 다운로드"는 --- page N --- 구분자와 함께 페이지를 순서대로 내보냅니다. DUPLICATE로 표시된 페이지는 이전 페이지와 텍스트가 동일했다는 뜻입니다 — 거의 항상 문서가 실제로 페이지를 넘기지 않았기 때문입니다.

페이지 자동 넘김 "캡처 후 자동으로 페이지 넘기기"를 켜고 다음 중 하나를 설정하세요:

  • 컨트롤 클릭 — "컨트롤 선택"을 누르고 뷰어의 다음 페이지 버튼을 클릭합니다. 저장되는 것은 CSS 셀렉터가 아니라 좌표(point)입니다.
  • 키 입력 — 키보드 이벤트(기본값 ArrowRight)를 캡처 영역 중앙을 소유한 프레임에 전달하여, 호스트 페이지가 아니라 리더가 이를 받게 합니다.

"지금 테스트"는 캡처 없이 즉시 페이지 넘김을 실행하고 결과를 보고합니다 — 긴 자동 실행을 시작하기 전에 사용할 가치가 있습니다.

셀렉터가 아닌 좌표인 이유 저장된 좌표는 CSS 셀렉터를 무효화하는 DOM 재렌더링을 survive하며, 셀렉터가 도달할 수 없는 두 곳에도 닿습니다:

  • 크로스 오리진 iframe. 대부분의 임베디드 리더는 iframe이며, 최상위 프레임이 표현할 수 있는 어떤 것도 그 내부 요소를 가리킬 수 없습니다.
  • Shadow DOM. document.querySelector는 섀도 루트 내부를 볼 수 없습니다.

페이지 넘김 시점에 좌표는 모든 프레임에 제시되고, 실제 그것을 소유한 프레임이 동작합니다. 각 프레임은 동일 오리진 조상을 거슬러 올라가며 자신이 최상위 뷰포트 안 어디에 있는지 계산합니다; 오리진 경계를 넘으면 부모…

원문 보기
원문 보기 (영어)
OCR It Pin a region once. Hit a hotkey on every page. Get the whole book as text. A Chrome extension for reading a paginated document trapped in a viewer — a scanned book, a slide deck, a PDF, a reader that won't let you select text. You drag out the capture region once . After that every press of the hotkey screenshots that exact rectangle, OCRs it, and appends the text to a running transcript. Or hand the whole job over: ⌥⇧A starts a run that captures, turns the page, and repeats until the document ends. Then paste the result wherever it's useful — an LLM being the obvious one, since a few hundred pages you couldn't select are now a text file you can hand to Claude or ChatGPT to summarise, search or ask questions about. OCR runs locally with a bundled Tesseract build. No API key, no network, no images leaving your machine — the extension makes no outbound requests at all. Install Download this repo or git clone it Open chrome://extensions and turn on Developer mode Load unpacked → select the folder Pin the extension — the toolbar icon doubles as the page counter Everything needed is committed. There's no build step: npm install is only for running the tests or re-vendoring Tesseract. Then check chrome://extensions/shortcuts and confirm the hotkeys landed — Chrome silently leaves them blank when something else already claims them. It asks for no site access at install. Single captures ride on activeTab , which Chrome hands over when you press the hotkey or open the popup. Two things need a durable grant — an auto-run that outlives a page load, and turning pages inside a cross-origin iframe — and the popup offers an Allow button for the site you're on when it matters. ⌥⇧S Capture the region once ⌥⇧A Start / stop an automatic run ⌥⇧R Draw or redraw the region Using it 1. Pin the region ⌥⇧R , then drag a box over the text. Before saving you can drag it around, pull the handles, or nudge it a pixel at a time with the arrow keys (hold ⇧ to resize). Enter keeps it. Draw a little inside the text margins — everything in the rectangle gets read, page numbers and running headers included. 2. Capture Press ⌥⇧S once per page. The screenshot is taken immediately and OCR runs in the background, so you never wait between pages — captures queue up and the badge counts what's still being read. 3. Or let it run Set up a next-page control (below) and ⌥⇧A takes over completely: capture, turn, capture, turn, until the document ends. Esc on the page stops it. 4. Export Every page is listed with a thumbnail of exactly what was cropped , so a drifted region is obvious at a glance instead of eighty pages later. Text is editable in place; a bad read can be re-run on its own. Copy all and Download .txt emit the pages in order with --- page N --- separators. A page marked DUPLICATE had text identical to the one before it — nearly always because the document didn't actually turn. Turning pages for you Enable Turn the page automatically after capture , then: Click a control — hit Pick control and click the viewer's next-page button. What gets stored is a point , not a CSS selector. Press a key — dispatches a keyboard event (default ArrowRight ) into whichever frame owns the middle of your capture region, so the reader gets it rather than the host page. Test now fires an advance immediately, without capturing, and reports what happened — worth using before starting a long run. Why a point rather than a selector A stored point survives the DOM re-renders that routinely invalidate a CSS selector, and it reaches two places a selector cannot: Cross-origin iframes. Most embedded readers are iframes, and nothing the top frame can express addresses an element inside one. Shadow DOM. document.querySelector can't see into a shadow root. At advance time the point is offered to every frame and the one that actually owns it acts. A frame works out where it sits inside the top-level viewport by walking up its same-origin ancestors; across an origin boundary the parent hands the offset down by postMessage . ( window.screenX is no help — inside an iframe it reports the browser window, not the frame.) The owning frame resolves the point through any shadow roots, walks up to the nearest real control, and emits the full pointerdown → mousedown → pointerup → mouseup → click sequence, so viewers that page on pointerdown behave like those listening for click . When it doesn't turn Every attempt records a verdict, shown in the popup and as an on-page toast: Verdict Meaning no next-page control picked yet Auto-advance is on but nothing was picked an embedded viewer owns that point Chrome's PDF viewer or a plugin — unreachable by any extension only the page background is at that point The control moved; pick it again a nested frame owns that point A frame that couldn't be injected into Because the target is a fixed point on screen, resizing the window or changing zoom mid-run breaks it , exactly as it breaks the capture region. Hands-off runs ⌥⇧A — or Start auto-run — captures, turns, and repeats on its own. Each cycle waits for that page's OCR to come back before turning. That costs nothing in practice (OCR is faster than a page turn) and buys the one thing an unattended loop needs: reliable end-detection . A run that only fired screenshots on a timer would sail past the last page and fill the transcript with copies of it. Stop it with Esc on the page, the hotkey, or the popup. It also stops itself when: Condition Default The text stops changing after 2 identical pages — you've hit the end The page can't be turned immediately, quoting the reason OCR fails or stalls immediately Page cap reached 300 pages The tab closes, or Chrome restarts immediately Whatever ended it is reported in the popup, so a run you walked away from never just stops being mysterious. A run refuses to start without a working next-page control rather than spinning on one page. PDFs Chrome's built-in PDF viewer works — text comes straight out of it. Draw the region over the page area (not the thumbnail sidebar) and page with your own ↓ / PageDown . Auto-advance does not work inside the PDF viewer, in either mode: the viewer is a plugin no extension can inject into, so a click lands on the <embed> , and its paging is native scrolling that synthetic key events can't drive. Since you're already pressing a hotkey per page, pressing your own page-down key costs nothing. For a PDF on disk ( file:///… ), open chrome://extensions → Details on OCR It → enable Allow access to file URLs . Chrome withholds file:// from every extension until you do. Settings Setting What it does Language English, Portuguese and Spanish ship with it — see below to add more Layout Tesseract's page segmentation. Single block suits one column of body text; Auto handles mixed layouts Sharpen crop before OCR Upscales the crop to ~2× and flattens it to a stretched greyscale ramp. Helps a lot on non-retina displays; leave it on Flag pages identical to the previous one Marks repeats as DUPLICATE and, in a run, ends it Auto-run Pause between pages, how many repeats end a run, and the hard page cap Adding a language Three ship with the extension — English, Portuguese and Spanish. Any of Tesseract's other ~100 languages can be added, but nothing is fetched at runtime, so the model has to be vendored into the extension first. npm install # once, for the tooling npm run vendor -- fra deu jpn # any tesseract language codes That pulls each <code>.traineddata.gz into vendor/lang/ . Then add the codes to LANGUAGES in src/shared.js so they appear in the popup's dropdown: export const LANGUAGES = [ { code : 'eng' , label : 'English' } , { code : 'por' , label : 'Portuguese' } , { code : 'spa' , label : 'Spanish' } , { code : 'fra' , label : 'French' } , // added ] ; Reload the extension at chrome://extensions and the new entry is there. Codes are the three-letter ones Tesseract uses: fra French, deu German, ita Italian, nld Dutch, rus Russian, jpn Japanese, chi_sim simplified Chi