📸 명함 이미지 & OCR 인식 완전 분석
명함 사진을 찍어서 AI가 글자를 읽어내는(OCR) 과정의 모든 단계와 소스코드를 분석합니다.
전체 흐름도
1. 사용자가 + 버튼 클릭 → add_paper_card()
2. 앱 카메라 열림 → 사용자가 명함 사진 촬영
3. 이미지 파일 → callAppBridge() → 네이티브 코드
4. 네이티브에서 서버로 이미지 업로드 (multipart/form-data)
5. 서버: [내부API]/[명함관리]
├── 이미지 파일 수신
├── OCR 엔진 호출 (아마도 Tesseract 또는 클라우드 OCR API)
├── 텍스트 추출: 이름, 직책, 회사명, 전화번호, 주소, 이메일, 팩스
└── JSON 응답: {name, mobile, org_name, job, addr, email, fax, img_url}
6. 클라이언트가 JSON 수신 → 모달 필드에 자동 채움
7. AI 알림 메시지 표시 (누락된 정보 안내)
이미지 관련 모달 요소
| 요소 ID | 역할 |
|---|---|
| #paper_img_url | OCR 처리된 이미지의 서버 URL (hidden input) |
| #paper_img_view_wrap | 이미지 영역 래퍼 (이미지 있을 때만 표시) |
| #paper_img_toggle_btn | "명함이미지보기" / "명함이미지닫기" 토글 버튼 |
| #paper_img_display | 실제 이미지 표시 영역 (기본 숨김) |
| #paper_card_img | <img> 요소 — 명함 이미지 표시 |
| #paper_ai_notice | AI 알림 박스 (누락 정보 경고) |
| #paper_ai_notice_msg | AI 알림 메시지 텍스트 |
이미지 토글 — togglePaperImg()
function togglePaperImg() {
var imgDisplay = document.getElementById('paper_img_display');
var btn = document.getElementById('paper_img_toggle_btn');
if (!imgDisplay) return;
if (imgDisplay.style.display === 'none') {
imgDisplay.style.display = 'block'; // 보이기
btn.innerHTML = btn.innerHTML.replace('명함이미지보기', '명함이미지닫기');
} else {
imgDisplay.style.display = 'none'; // 숨기기
btn.innerHTML = btn.innerHTML.replace('명함이미지닫기', '명함이미지보기');
}
}
OCR 응답 처리 로직
앱에서 촬영한 이미지가 서버에서 OCR 처리된 후, 다음과 같은 JSON 응답이 옵니다:
// 서버 응답 예시 (OCR 결과)
{
"name": "홍길동",
"mobile": "010-1234-5678",
"org_name": "ABC컴퍼니",
"job": "대표이사",
"addr": "서울시 강남구 테헤란로 123",
"email": "hong@abc.com",
"fax": "02-123-4567",
"img_url": "[내부경로]/[데이터]/abc123.jpg"
}
// 클라이언트 처리:
if (imgUrl) {
document.getElementById('paper_img_url').value = imgUrl; // 숨은 필드에 저장
document.getElementById('paper_card_img').src = imgUrl; // 이미지 표시
imgWrap.style.display = 'block'; // 이미지 래퍼 표시
} else {
imgWrap.style.display = 'none'; // 이미지 없으면 숨김
}
// 이미지 표시 영역은 접힌 상태로 시작 (imgDisplay.style.display = 'none')
AI 알림 (누락 정보 경고)
OCR이 모든 정보를 완벽하게 읽지 못했을 때 표시되는 경고 메시지입니다:
// 필수 필드 체크
var missing = [];
if (!data.name || data.name.trim() === '') missing.push('이름');
if (!data.mobile || data.mobile.trim() === '') missing.push('휴대전화');
if (!data.org_name || data.org_name.trim() === '') missing.push('소속(기관명)');
if (missing.length > 0) {
noticeMsgEl.textContent =
'안녕하세요? IAM AI입니다. 지금 촬영 과정에서 ' +
missing.join(', ') + ' 등의 정보가 명확하지 않으니 ' +
'회원님의 최종 확인을 부탁합니다.';
noticeEl.style.display = 'block'; // 알림 표시
} else {
noticeEl.style.display = 'none'; // 모든 정보 있으면 숨김
}
💡 초등학생을 위한 비유: OCR은 마치 선생님이 학생의 글씨를 읽는 것과 같아요. 명함 사진이라는 '그림'을 보고 AI 선생님이 거기 적힌 글자를 찾아내는 거예요. 하지만 글씨가 너무 흐리거나 이상한 글씨체면 AI 선생님도 실수할 수 있어서, "이 부분을 다시 확인해 주세요~"라고 친절하게 알려줘요!
이미지 크기 조정 — resize()
function resize(img, maxW, maxH) {
var width = img.width;
var height = img.height;
// 1단계: 너비가 최대치 초과하면 비율 유지하며 축소
if (width > maxW) {
ratio = maxW / width;
$("#card_logo").css("width", maxW);
$("#card_logo").css("height", height * ratio);
height = height * ratio;
}
// 2단계: 높이가 최대치 초과하면 비율 유지하며 축소
width = $("#card_logo").width();
height = $("#card_logo").height();
if (height > maxH) {
ratio = maxH / height;
$("#card_logo").css("height", maxH);
$("#card_logo").css("width", width * ratio);
}
}
// 주로 #card_logo (명함 로고 이미지)에 사용됨
앱 카메라 흐름 상세
사용자 클릭 → add_paper_card()
↓
callAppBridge('goCardCamera')
├── Android: AppScript.goCardCamera() (네이티브 카메라 인텐트)
└── iOS: webkit.messageHandlers['goCardCamera'].postMessage()
↓
네이티브 카메라 열림 → 사용자 촬영
↓
이미지 파일 생성 → 네이티브 코드가 HTTP POST로 서버 전송
↓
서버 OCR 처리 → JSON 응답
↓
WebView로 JSON 콜백 → 클라이언트 JavaScript 수신
↓
모달 필드 자동 채움 + AI 알림 표시