FreeBSD 환경에서 완벽하게 동작하며, in 디렉터리의 이벤트를 감지하여 자동으로 out 디렉터리에 텍스트를 추출하는 C 언어 기반 데몬(Daemon) 프로그램의 전체 소스 코드입니다. 요청하신 "인식률 향상"을 위해 C 코드 내부에서 PDF를 300 DPI의 고해상도 흑백(Grayscale) 이미지로 1차 변환 한 뒤, Tesseract의 신경망(LSTM) 모드와 문서 구조 인식(PSM 6)을 결합하여 처리하도록 설계했습니다. 무한 반복을 방지하기 위해 처리가 끝난 PDF는 done 디렉터리로 이동합니다. 1. 필수 패키지 설치 FreeBSD 시스템에 PDF 변환 도구( poppler )와 OCR 엔진( tesseract ), 한글/영문 학습 데이터를 먼저 설치해야 합니다. Bash pkg install poppler-utils tesseract tesseract-data-kor tesseract-data-eng 2. 전체 소스 코드 ( pdf_ocr_daemon.c ) 코드의 생략이나 누락 없이 완전한 전체 소스 코드를 제공합니다. FreeBSD의 고유 파일 시스템 이벤트 모니터링 기능인 kqueue 를 사용하여 리소스 낭비 없이 파일 생성을 즉각 감지합니다. C #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <dirent.h> #include <sys/types.h> #include <sys/event.h> #include <sys/time.h> #include <sys/stat.h> #include <syslog.h> #include <errno.h> #define DIR_IN "in" #define DIR_OUT "out" #define DIR_DONE "done" // PDF를 처리하고 텍스트를 추출하는 함수 void process_pdf(const char *filename) { char in_path[512], out_path[512], done_path[512]; char cmd[2048]; snprintf(in_path, sizeof(in_path), "%s/%s", DIR_IN, filename); // 확장자를 제외한 파일명 추출 char basename[256]; strncpy(basename, filename, sizeof(basename)); char *dot = strrchr(basename, '.'); if (dot) *dot = '\0'; snprintf(out_path, sizeof(out_path), "%s/%s.txt", DIR_OUT, basename); snprintf(done_path, sizeof(done_path), "%s/%s", DIR_DONE, filename); syslog(LOG_INFO, "Processing started: %s", in_path); pid_t pid = getpid(); // 1단계: 인식률 극대화를 위한 PDF -> 300 DPI 흑백 이미지(PGM) 변환 snprintf(cmd, sizeof(cmd), "pdftoppm -gray -r 300 \"%s\" \"/tmp/ocr_%s_%d\"", in_path, basename, pid); system(cmd); // 2단계: 생성된 고해상도 이미지들에 대해 Tesseract OCR 수행 및 텍스트 누적 병합 // --oem 3 (기본 LSTM 신경망), --psm 6 (단일 텍스트 블록 가정) 적용 snprintf(cmd, sizeof(cmd), "for img in /tmp/ocr_%s_%d-*.pgm; do " " if [ -f \"$img\" ]; then " " tesseract \"$img\" stdout -l kor+eng --oem 3 --psm 6 >> \"%s\" 2>/dev/null; " " rm -f \"$img\"; " " fi; " "done", basename, pid, out_path); system(cmd); // 3단계: 무한 루프 방지를 위해 처리 완료된 PDF 이동 if (rename(in_path, done_path) == 0) { syslog(LOG_INFO, "Processing finished: saved to %s", out_path); } else { syslog(LOG_ERR, "Failed to move %s to %s", in_path, done_path); } } // in 디렉터리를 스캔하여 PDF 파일을 찾는 함수 void scan_directory() { DIR *dir = opendir(DIR_IN); if (!dir) return; struct dirent *ent; while ((ent = readdir(dir)) != NULL) { if (ent->d_type == DT_REG) { char *dot = strrchr(ent->d_name, '.'); // 대소문자 구분 없이 PDF 확인 if (dot && (strcmp(dot, ".pdf") == 0 || strcmp(dot, ".PDF") == 0)) { // 대용량 PDF 파일이 네트워크나 디스크에서 완전히 복사될 시간을 벌어줌 sleep(2); process_pdf(ent->d_name); } } } closedir(dir); } int main() { // 작업에 필요한 필수 디렉터리 생성 mkdir(DIR_IN, 0755); mkdir(DIR_OUT, 0755); mkdir(DIR_DONE, 0755); // FreeBSD 백그라운드 데몬으로 전환 (working directory 유지, stdout/err는 /dev/null) if (daemon(1, 0) == -1) { perror("daemon"); exit(EXIT_FAILURE); } // syslog 초기화 (데몬의 로그는 /var/log/messages에서 확인 가능) openlog("pdf_ocr_daemon", LOG_PID, LOG_DAEMON); syslog(LOG_INFO, "PDF OCR Daemon started using kqueue"); // 데몬 시작 시점에 이미 들어와 있는 파일 선처리 scan_directory(); // kqueue 초기화 및 in 디렉터리 오픈 int kq = kqueue(); int fd = open(DIR_IN, O_RDONLY); if (kq == -1 || fd == -1) { syslog(LOG_ERR, "Failed to initialize kqueue or open input directory"); exit(EXIT_FAILURE); } struct kevent change; // 디렉터리에 쓰기(파일 생성/이동) 이벤트가 발생할 때 알림 등록 EV_SET(&change, fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR, NOTE_WRITE, 0, 0); struct kevent event; for (;;) { // 이벤트 대기 (블로킹 모드 - CPU 점유율 0%) int nev = kevent(kq, &change, 1, &event, 1, NULL); if (nev > 0) { if (event.fflags & NOTE_WRITE) { // 파일 추가 이벤트 감지 시 디렉터리 스캔 scan_directory(); } } } // 도달하지 않는 코드이지만 리소스 정리 명시 close(fd); close(kq); closelog(); return 0; } 3. 컴파일 및 실행 방법 작성된 소스 코드를 컴파일하고 실행하는 절차입니다. 1. 컴파일 (GCC 또는 Clang 사용) FreeBSD에 내장된 clang 을 사용하여 컴파일합니다. Bash cc -O2 -o pdf_ocr_daemon pdf_ocr_daemon.c 2. 데몬 실행 컴파일된 실행 파일을 실행하면 자동으로 백그라운드(Daemon)로 들어가며, 현재 경로에 in , out , done 디렉터리를 자동 생성합니다. Bash ./pdf_ocr_daemon 3. 동작 테스트 및 로그 확인 in 디렉터리에 임의의 한글 PDF 파일을 복사합니다. Bash cp sample.pdf in/ 동작 상태는 FreeBSD의 시스템 로그를 통해 실시간으로 확인할 수 있습니다. Bash tail -f /var/log/messages | grep pdf_ocr_daemon 4. 데몬 종료 데몬 프로세스를 종료하려면 다음 명령을 사용합니다. Bash killall pdf_ocr_daemon