범위와 스택
v1 은 인물 사진 한 장을 한국 여권·운전면허증·주민등록증 사진이나 일반 35×45mm·30×40mm 사진으로 만듭니다. 단일 JPEG 또는 4×6인치 인화 배치를 갤러리에 저장하고, 저장한 파일을 공유할 수 있습니다. 계정·서버·사진 보관함은 없으며, 한 번에 작업 하나만 편집하고 작업 사이에 아무것도 남기지 않습니다.
| UI | Kotlin·Jetpack Compose, minSdk 29, targetSdk 36 |
|---|---|
| 입력 | CameraX 촬영(전면·후면 카메라, 3초 타이머 선택) 또는 Android Photo Picker(이미지만) |
| 얼굴 확인 | 앱에 포함된 ML Kit Face Detection — 빠른 모드, 눈 뜸 분류 포함 |
| 배경 | 앱에 포함된 ML Kit Selfie Segmentation — 단일 이미지 모드, 일반 사진에만 |
| 출력 | MediaStore 로 Pictures/DotoriIdPhoto 에 쓰는 300dpi JPEG, 저장한 파일의 공유 시트 |
| 광고 | 홈 화면에만 AdMob 배너, UMP 동의 |
두 ML Kit 래퍼는 공용 libs/ai 아래 face-detection·selfie-segmentation 에 있습니다. 이들이 맡는 것은 SDK 호출과 해제, 그리고 중립 결과 — 바로 세운 이미지 기준으로 정규화한 얼굴 박스와 roll·yaw·눈 뜸 확률, 또는 전경 신뢰도 마스크 — 뿐입니다. 규격·크롭·확인·출력은 앱이 소유합니다. 도토리 명함 스캐너가 쓰는 OCR 쪽 libs/ai/core 에는 의존하지 않습니다.
공식 규격과 앱이 검사하는 것
프리셋은 2026년 9월 23일에 확인한 정부 안내를 따릅니다. 앱은 물리 크기와 파일 제한을 스스로 지킬 수 있는 규칙으로, 사진 속 사람에 관한 것은 모두 사용자가 확인할 규칙으로 나눕니다.
| 여권 | 35×45mm. 온라인 파일은 JPEG 500KB 이하, 413×531px 권장. 흰색 원본 배경. 머리카락을 제외한 정수리~턱 32~36mm. 출처: 외교부 여권 사진 규정, 온라인 신청 안내. |
|---|---|
| 운전면허증 | 35×45mm. 현재 공단 안내의 온라인 파일은 JPG 500KB 이하, 413×531px. 편집·합성하지 않은 사진이어야 합니다. 출처: 도로교통공단. |
| 주민등록증 | 35×45mm. 흰색 배경 권장, 옅은 단일색 가능. 별도 온라인 파일 규격은 확인하지 못해, 앱은 용량 제한 없이 단일 파일과 인화 배치를 제공합니다. 출처: 행정안전부. |
| 일반 | 35×45mm 또는 30×40mm. 앱 편의 프리셋이며 공인 규격이 아닙니다. |
- 앱이 검사합니다. 고른 용도의 가로세로 비율, 크롭 영역이 출력 픽셀 수 이상인지, 출력 픽셀 크기와 300dpi 표기, 여권·면허 단일 파일의 500,000바이트 제한.
- 사용자가 확인합니다. 구도와 여백, 머리 크기, 자세, 눈, 조명, 배경, 촬영 시기. 도움말에 여권의 정수리~턱 규정을 적고 외교부 여권 사진 규정으로 연결합니다.
- 하지 않습니다. 머리 길이를 측정하지 않고, 접수 적합성을 판정하지 않으며, 기관이 사진을 받아 줄 것을 보장하지 않습니다. 세 신분증의 통합 규격도 확인하지 못해 가정하지 않습니다.
입력과 얼굴 확인
용도를 먼저 고릅니다. 용도가 가로세로 비율·초기 틀·배경 도구 유무를 정하기 때문입니다. 용도를 바꾸면 새 작업이 됩니다.
- 고른 이미지는 32MiB 제한으로 앱 캐시의 임시 파일에 복사하고, 디코드 직후 그 복사본을 지웁니다. 촬영본도 같은 캐시 폴더에 쓰고 디코드 뒤 지웁니다. 선택기 URI 는 저장하지 않습니다.
ImageDecoder가 EXIF 회전·반전을 픽셀에 적용하고 sRGB 로 바꾸며 긴 변을 2048px 로 제한합니다. 한 변이 30,000px 를 넘는 이미지는 디코드 전에 거부합니다.- 얼굴 검출은 긴 변 768px 이하의 사본에서 돌립니다. contour 모드는 가장 두드러진 얼굴 하나만 보고해 두 번째 사람을 가리므로 쓰지 않습니다.
- 얼굴이 정확히 하나일 때만 편집에 들어갑니다. 얼굴 없음·여러 명·검출기 실패 모두 안내와 함께 홈 화면에 머뭅니다. 얼굴을 확인하지 못한 사진은 통과가 아니라 미확인으로 봅니다.
- 사용자가 취소한 뒤 도착한 결과는 적용하지 않고, 작업이 도는 동안 다른 작업을 시작할 수 없습니다.
촬영 화면도 최대 500ms 마다 미리보기 한 프레임에 검출기를 돌려 “한 사람만 나오도록 촬영하세요”, “정면을 보고 얼굴을 가운데 맞추세요” 같은 안내를 띄웁니다. 이 안내와 편집 화면의 자세·눈 뜸 경고는 조언일 뿐이며 촬영이나 저장을 막지 않습니다.
카메라 권한은 사용자가 촬영을 고를 때만 요청하고, 사진 선택에는 저장소·미디어 권한이 필요 없습니다. 앱 manifest 가 직접 선언한 권한은 CAMERA 하나이며 카메라는 필수 기능이 아닌 것으로 표시합니다.
크롭 틀과 초기 구도
미리보기의 상단·하단 선은 저장할 사진의 경계이지 측정선이 아닙니다. 이전 빌드는 추정한 정수리·턱 선과 자동 구도 버튼이 있었으나 사용자 피드백으로 둘 다 없앴습니다.
- 경계 손잡이. 오른쪽 두 손잡이 중 하나를 끌면 반대쪽 경계는 그대로 두고 그 경계만 움직이며, 너비는 용도의 가로세로 비율에서 따라 정해집니다. 틀은 원본 밖으로 나갈 수 없고, 뒤집히지 않으며, 가능한 최대 틀의 15% 보다 작아지지 않습니다.
- 틀 이동. 틀 안쪽을 끌면 크기를 유지한 채 상하좌우로 움직입니다. 이동량을 드래그 시작점부터 누적하므로, 틀이 사진 가장자리에 막힌 뒤 손가락을 되돌려도 틀과 손가락이 어긋나지 않습니다. touch slop 미만의 탭·떨림은 드래그가 아니며 구도 확인을 풀지 않습니다.
- 터치 판정. 손잡이를 잡았는지 틀을 잡았는지는 마지막으로 그린 틀이 아니라 터치 순간의 모델 상태로 판정합니다. 새 터치가 재구성보다 먼저 올 수 있기 때문입니다.
- 보이는 틀. 저장 틀은 흰 선 양옆에 어두운 테를 둔 선이라 흰 벽에서도 어두운 음영에서도 보이고, 끄는 동안 굵어집니다. 원본 이미지에도 얇은 외곽선을 그립니다.
얼굴 박스는 손잡이의 시작 위치 하나에만 씁니다. ML Kit 박스가 대략 이마부터 턱까지이므로 머리 길이를 박스 높이의 1.3배로 추정합니다. 머리가 사진 높이에서 차지하는 비율은 용도별입니다. 세 신분증 용도는 여권 32~36mm 규정의 중앙값인 34/45(약 76%), 일반 사진은 어깨가 더 보이도록 60% 입니다. 남은 높이는 정수리 위 1 : 턱 아래 2 로 나누고, 가로는 얼굴 중심에 맞춥니다.
1.3 은 검증하지 않은 추정값입니다. 실제 인물 사진으로 확인하지 않았고, 원본이 짧거나 얼굴이 가장자리에 붙으면 원본 안으로 자르느라 한쪽 여백이 줄어듭니다. 그래서 얼굴 박스로 안내선을 그리거나 합격 여부를 정하거나 저장을 막지 않습니다. “머리 위 주먹 하나, 턱 아래 주먹 둘” 규칙은 비율로만 씁니다. 주먹을 실제 크기로 쓰면 머리가 사진 높이의 약 45% 가 되어 여권 규정에 크게 못 미칩니다.
경계 손잡이는 접근성 서비스에 진행 값과 이름을 노출합니다. 틀의 좌우 이동에는 아직 별도 접근성 조작이 없습니다.
배경
여권 규정은 배경 제거와 흰 배경 합성을 금지하고, 운전면허 안내는 편집·합성 사진을 금지합니다. 주민등록증에는 앱이 자체 방침으로 같은 규칙을 적용합니다. 세 신분증 용도 모두 배경 도구를 보여 주지 않고, 저장 파일은 언제나 원본 픽셀로 만듭니다.
- 일반 사진은 원본·흰색·하늘색 세 가지 배경 칩을 제공합니다.
- Selfie Segmentation 은 768px 분석 사본에서 돌며,
enableRawSizeMask설정이라 그 분석 사본과 같은 크기(긴 변 768px 이하)의 신뢰도 마스크를 돌려줍니다. 마스크를 원본 크기로 늘려 alpha 로 써서 인물을 단색 위에 얹고, 원본 비트맵은 그대로 두므로 “원본”을 다시 고르면 정확히 되돌아옵니다. - 마스크는 사진마다 한 번만 계산해 색을 바꿀 때 재사용합니다. 분할이 실패하면 원본을 유지하고 다시 시도할 수 있습니다.
- 배경을 바꾸면 “배경 경계 확인”이 풀립니다. 머리카락·어깨 경계는 사용자가 확인할 몫입니다.
저장 조건과 출력 파일
저장 버튼과 그 위의 안내 문구는 한 함수 saveBlocker 에서 나옵니다. 그래서 안내가 설명하지 못하는 이유로 버튼이 열리거나 닫히지 않습니다. 검사 순서는 사진 없음, 작업 진행 중, 구도 미확인, 규정·배경 경계 미확인, 출력 크기보다 작은 크롭입니다. 여러 얼굴은 편집 단계에 오지 못하므로 저장 사유에 없습니다. 경계나 틀을 움직이면 구도 확인만 풀리고 규정 확인은 유지됩니다.
| 픽셀 크기 | mm ÷ 25.4 × 300 반올림: 35×45mm 는 413×531px, 30×40mm 는 354×472px |
|---|---|
| 배율 | 축소만 합니다. 출력보다 픽셀이 적은 크롭은 확대해서 감추지 않고 해상도 부족으로 막습니다. |
| JPEG | 품질 95 에서 60 까지 5씩 낮추며 실제 인코딩 크기를 검사합니다. 여권·면허 단일 파일은 500,000바이트 이하여야 하며, 품질 60 에서도 넘으면 저장이 실패합니다. |
| 메타데이터 | 300dpi 해상도와 정방향만 담은 새 EXIF. 원본에서 아무것도 복사하지 않으므로 GPS·카메라 메타데이터가 출력에 가지 않습니다. |
| 인화 배치 | 1200×1800px(300dpi 4×6인치): 35×45mm 6매 또는 30×40mm 9매, 사진 간격 24px, 회색 모서리 표시와 사진 바깥 1px 간격의 연회색 재단선. 사진 픽셀은 바뀌지 않고, 단일 파일에는 테두리가 없습니다. |
- 파일은 대기(pending) 상태의 MediaStore 항목으로 쓰고, 파일을 다 쓴 뒤에만 공개하며, 도중에 실패하면 그 항목을 지웁니다. 원본 파일을 덮어쓰지 않습니다.
- 파일 이름에는 사람 이름 대신 시각과 파일 종류를 넣습니다. 저장을 동시에 두 번 시작할 수 없고, 진행 중인 저장은 중간에 취소되지 않습니다.
- 공유는 저장한 MediaStore URI 를 읽기 권한과 함께 사용자가 고른 앱에 보냅니다. 갤러리 보기 버튼은 기기 갤러리 앱을 열며 저장 조건과 무관하게 쓸 수 있습니다.
- 인화 배치는 확대·자동 잘림 없이 실제 크기로 인화해야 하며, 도움말에 이를 적습니다.
저장·개인정보·백업
인물 사진은 찍힌 사람의 개인정보이므로 앱은 자기 사본을 남기지 않습니다.
- 편집 중인 사진은 ViewModel 의 메모리에 있습니다. 화면 회전은 견디지만 프로세스가 종료되면 사라지고, 다음 실행은 사진 없이 시작합니다.
- 앱 캐시의 임시 파일은 ViewModel 시작, 용도 변경, 저장 직후, ViewModel 해제 때 지웁니다.
- manifest 가
allowBackup="false"·fullBackupContent="false"이고,dataExtractionRules가 앱 저장소 전체를 클라우드 백업과 기기 간 이전에서 뺍니다. - 얼굴 검출과 분할은 앱에 포함된 모델을 씁니다. 처리를 위해 사진을 업로드하지 않고 광고 요청에 붙이지 않습니다. ML Kit 자체 진단과 광고 SDK 의 통신은 별개이며 처리방침에 적습니다.
- 갤러리에 저장한 파일은 갤러리 소관입니다. 갤러리나 클라우드 사진 서비스의 백업 여부는 앱이 제어하지 않으며, 나중에 지워도 이미 공유한 사본은 회수되지 않습니다.
- 생성형 AI 기능, 뷰티 필터, 보정·톤 변경은 없습니다.
검증과 확인된 제약
크롭 기하(세로·가로 원본, 경계 끌기, 틀 이동, 인화 배치, 가장자리 얼굴의 초기 구도)와 저장 조건은 JVM 단위 시험으로 확인합니다. Android 11 시험 폰의 계측 시험 3건이 출력 픽셀 크기·dpi·용량 제한, EXIF 회전과 GPS 제거, MediaStore 공개, 배경 합성이 전경과 원본을 보존하는지를 확인합니다.
기기에서 잰 값. 저장한 35×45mm 단일 파일을 다시 읽어 413×531px·300dpi, 15,042바이트와 43,355바이트를 확인했습니다. 같은 폰에서 상단 손잡이를 끌 때 하단 경계가 유지되고 그 반대도 성립하는 것, 조절 영역을 스크롤해도 저장 버튼 위치가 그대로인 것, 갤러리 보기가 Samsung 갤러리를 여는 것을 확인했습니다. 시험 촬영에는 인물이 없었으므로 인식률이나 접수 적합성에 관해서는 아무것도 말해 주지 않습니다.
- 시스템 사진 선택기에서 선택을 마치는 과정은 선택기가 열리는 데까지만 확인했습니다.
- 첫 실행 오프라인 처리와 실제 인물의 분할 경계 품질은 아직 실측하지 않았고, 두 번째 기기에서도 재지 않았습니다.
- 작업 중 화면 회전·백그라운드 전환은 기기에서 실측하지 않았습니다.
- 머리 1.3배는 추정값이라 사진마다 초기 틀을 조정해야 할 수 있습니다.
- 한국 규격만 있습니다. 해외 여권·비자 규격, 사진 보관함, ML Kit Subject Segmentation 은 v1 범위 밖입니다.
- 틀의 좌우 이동에는 드래그 외의 접근성 대안이 없습니다.