본문 바로가기

Web/javascript

[javascript] 웹페이지 잘리지 않게 PDF 파일로 만들기

 

먼저 준비물

    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/bluebird/3.7.2/bluebird.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.5.3/jspdf.min.js"></script>
    <script src="https://unpkg.com/html2canvas@1.0.0-rc.5/dist/html2canvas.js"></script>

bluebird는 익스플로러에서 작동하게 하려면 꼭 필요하다.

jspdf는 pdf 생성해주는 라이브러리,

html2canvas는 html 페이지를 이미지로 만들어주는 라이브러리이다.

 

주의사항

html2canvas는 html페이지와 같은 도메인에 올라가 있는 이미지만 불러올 수 있는 것 같다.

외부 cdn 이미지를 이용하면 출력되지 않는다.

(https://stackoverflow.com/questions/31509227/html2canvas-not-rendering-cdn-images)

pixabay에 있는 이미지 주소로 이미지를 넣고 실행하니까 전혀 나오지 않아서 찾아보니 이런 내용이 있다.

그래서 따로 호스팅을 파서 같이 올리니 실행이 됨.

 

데모

http://gyl13.dothome.co.kr/demo/createPdf.html

 

createPdf

 

gyl13.dothome.co.kr

상단의 PDF 만들기 버튼을 누르면 PDF 파일이 다운로드된다.

 

var renderedImg = new Array;

var contWidth = 200, // 너비(mm) (a4에 맞춤)
		padding = 5; //상하좌우 여백(mm)

function createPdf() { //이미지를 pdf로 만들기
	document.getElementById("loader").style.display = "block"; //로딩 시작

	var lists = document.querySelectorAll("ul.pdfArea > li"),
			deferreds = [],
			doc = new jsPDF("p", "mm", "a4"),
			listsLeng = lists.length;

	for (var i = 0; i < listsLeng; i++) { // li 개수만큼 이미지 생성
		var deferred = $.Deferred();
		deferreds.push(deferred.promise());
		generateCanvas(i, doc, deferred, lists[i]);
	}

	$.when.apply($, deferreds).then(function () { // 이미지 렌더링이 끝난 후
		var sorted = renderedImg.sort(function(a,b){return a.num < b.num ? -1 : 1;}), // 순서대로 정렬
				curHeight = padding, //위 여백 (이미지가 들어가기 시작할 y축)
				sortedLeng = sorted.length;
	
		for (var i = 0; i < sortedLeng; i++) {
			var sortedHeight = sorted[i].height, //이미지 높이
					sortedImage = sorted[i].image; //이미지

			if( curHeight + sortedHeight > 297 - padding * 2 ){ // a4 높이에 맞게 남은 공간이 이미지높이보다 작을 경우 페이지 추가
				doc.addPage(); // 페이지를 추가함
		curHeight = padding; // 이미지가 들어갈 y축을 초기 여백값으로 초기화
				doc.addImage(sortedImage, 'jpeg', padding , curHeight, contWidth, sortedHeight); //이미지 넣기
				curHeight += sortedHeight; // y축 = 여백 + 새로 들어간 이미지 높이
			} else { // 페이지에 남은 공간보다 이미지가 작으면 페이지 추가하지 않음
				doc.addImage(sortedImage, 'jpeg', padding , curHeight, contWidth, sortedHeight); //이미지 넣기
				curHeight += sortedHeight; // y축 = 기존y축 + 새로들어간 이미지 높이
			}
		}
		doc.save('pdf_test.pdf'); //pdf 저장

		document.getElementById("loader").style.display = "none"; //로딩 끝
		curHeight = padding; //y축 초기화
		renderedImg = new Array; //이미지 배열 초기화
	});
}

function generateCanvas(i, doc, deferred, curList){ //페이지를 이미지로 만들기
	var pdfWidth = $(curList).outerWidth() * 0.2645, //px -> mm로 변환
			pdfHeight = $(curList).outerHeight() * 0.2645,
			heightCalc = contWidth * pdfHeight / pdfWidth; //비율에 맞게 높이 조절
	html2canvas( curList ).then(
		function (canvas) {
			var img = canvas.toDataURL('image/jpeg', 1.0); //이미지 형식 지정
			renderedImg.push({num:i, image:img, height:heightCalc}); //renderedImg 배열에 이미지 데이터 저장(뒤죽박죽 방지)     
			deferred.resolve(); //결과 보내기
			}
	);
}

pdf 파일 안의 이미지 순서가 뒤죽박죽이라

따로 배열을 만들어서 순서대로 다시 배열하는 부분을 넣어야 했다.

 

html2canvas 관련 내용을 찾다 보면 onrendered가 들어간 코드들이 많이 보이는데,

개발자가 이 부분을 수정해서 더이상 사용이 안 된다.

html2canvas().then() 으로 해야 함.