도구 · 제작기

PDF 합치기·나누기

프로젝트 소개

무엇인가

여러 PDF와 사진을 한 PDF로 합치고, 쪽 순서를 바꾸고, 필요한 쪽만 뽑거나 여러 파일로 나누는 도구입니다. 제출 서류 여러 개를 하나로 묶거나, 스캔한 영수증 사진을 PDF 한 개로 만들거나, 두꺼운 보고서에서 몇 쪽만 떼어 보낼 때 씁니다. 파일은 서버로 올라가지 않습니다. 읽고 붙이는 일을 모두 이 브라우저 안에서 하므로 계약서나 신분증 사본도 그대로 넣을 수 있습니다.

이렇게 써보세요

자료와 방법

미리보기는 모질라의 오픈소스 PDF 엔진 pdf.js(3.11.174)로 그리고, 새 PDF는 pdf-lib(1.17.1)로 만듭니다. 원본 PDF의 쪽은 그림으로 다시 그리지 않고 쪽 내용을 그대로 복사하므로 글자 선택과 검색, 화질이 원본과 같습니다. 같은 파일에서 온 쪽은 한 번에 복사해 글꼴 같은 공용 자원이 두 번 들어가지 않게 합니다. 사진 가운데 회전 정보가 없는 JPG와 PNG는 원본 바이트를 그대로 넣어 다시 압축하지 않습니다. 휴대폰으로 돌려 찍은 JPG(EXIF 방향 값이 있는 사진)와 WebP 같은 형식은 브라우저가 바로 세운 그림을 화질 92의 JPG로 다시 만들어 넣습니다. ZIP은 JSZip(3.10.1)으로 묶습니다.

한계와 주의

PDF 도구를 세 개 만든 뒤 운영자가 다음에 무엇을 만들지 물었다. 내가 낸 후보 여덟 개 가운데 운영자는 "PDF 합치기·나누기"와 "사진을 PDF로"를 묶어 달라고 했다. 둘 다 결국 여러 조각을 받아 쪽 목록 하나로 늘어놓고 원하는 순서로 다시 묶는 일이라 화면 하나로 충분했다.

다시 그리지 않고 옮기기

PDF→이미지 도구는 pdf.js로 쪽을 캔버스에 그렸다. 합치기에서 같은 방법을 쓰면 글자가 그림이 되어 선택도 검색도 안 되고 파일이 몇 배로 커진다. 그래서 미리보기만 pdf.js로 그리고, 결과 PDF는 pdf-lib(1.17.1)로 원본 쪽의 내용 스트림을 그대로 복사해서 만들었다.

처음에는 쪽마다 따로 복사하도록 짰다가 고쳤다. pdf-lib의 copyPages는 한 번 부를 때마다 그 쪽이 쓰는 글꼴과 그림을 새로 복사한다. 같은 파일에서 온 23쪽을 하나씩 복사하면 같은 한글 글꼴이 23번 들어갈 수 있다. 지금은 원본 파일마다 필요한 쪽을 모아 한 번에 복사하고, 순서는 그 뒤에 맞춘다. 시험에서 533KB짜리 23쪽 PDF에 사진 넷을 섞고 쪽 하나를 뺀 결과는 478KB였고, 3쪽의 글자를 뽑아 원본 3쪽과 비교하니 같았다.

누워 있는 사진

휴대폰 사진은 센서 방향 그대로 저장되고, 세워서 보여 줄지는 EXIF의 방향 값에 적혀 있다. JPG를 PDF에 그대로 넣으면 PDF 보기 프로그램은 이 값을 읽지 않아서 세로로 찍은 사진이 옆으로 눕는다. JPG 앞부분을 직접 읽어 방향 값을 찾고, 값이 1(그대로)인 JPG와 PNG만 원본 바이트를 그대로 넣었다. 나머지는 브라우저가 세운 그림을 화질 92의 JPG로 다시 만든다. 시험용으로 가로 1200×800에 방향 값 6을 넣은 사진을 만들었고, 결과 PDF에서 A4 세로 쪽에 바로 선 것을 확인했다.

암호가 걸린 PDF

pdf-lib은 암호가 걸린 PDF를 열지 못한다. 열 때 쓰는 비밀번호가 없고 편집만 막은 PDF도 마찬가지다. pdf.js는 둘 다 열 수 있으므로, pdf-lib이 거절한 파일은 pdf.js로 쪽을 200dpi로 그려 그림으로 넣었다. 대신 파일 이름 옆에 '그림으로'라고 붙여 이 쪽은 글자를 검색할 수 없다는 것을 알 수 있게 했다. pypdf로 열람 비밀번호가 있는 파일과 편집만 막은 파일을 하나씩 만들어 넣어 보니, 틀린 비밀번호는 다시 묻고 맞는 비밀번호를 넣으면 다섯 쪽 모두 들어갔다.

손가락으로 끌기

마우스는 6픽셀 넘게 움직이면 끌기가 시작된다. 휴대폰에서 같은 규칙을 쓰면 화면을 스크롤하려던 손가락이 쪽을 집어 버린다. 그래서 터치는 0.28초 동안 누르고 있어야 끌기가 시작되고, 그 전에 10픽셀 넘게 움직이면 스크롤로 본다. 끌기가 시작된 뒤에는 touchmove를 막아 화면이 따라 움직이지 않게 했다. 선택한 쪽이 여럿이면 그중 하나를 끌 때 모두 함께 옮겨지고, 화면 끝에 가까이 가면 목록이 저절로 스크롤된다.

이름이 겹친 버튼

마지막 시험에서 비밀번호 창의 '취소' 버튼이 상자 밖 왼쪽에 기울어진 채 떠 있었다. 끌 때 손가락 아래 따라다니는 작은 그림에 ghost라는 클래스 이름을 붙였는데, 기존 PDF 도구에서 가져온 회색 버튼 이름도 btn ghost였다. 끌기용 스타일(화면에 고정, 3도 기울이기)이 버튼에 그대로 입혀진 것이다. 끌기용 이름을 dragghost로 바꿨다.

결과

PDF 하나와 사진 넷(JPG 둘, PNG, WebP)을 넣고 돌리기, 빼기, 마우스와 터치로 끌기, Alt+화살표로 옮기기, 되돌리기를 차례로 해 본 뒤 저장했다. 26쪽이 화면 순서 그대로 나왔고, 돌린 쪽의 회전 값과 사진 쪽의 A4 가로·세로도 맞았다. 한 쪽씩 나누기는 26개, "1-3, 9" 범위 나누기는 3쪽과 1쪽짜리 두 개가 ZIP에 들어갔다.

PDF 합치기·나누기 실제로 써보기 ghmun.com/merge 가기 →