브라우저에서 이미지, pdf 파일 drag & drop 업로드 및 미리보기 구현하기

abi hong·2023년 12월 22일
0

Frontend

목록 보기
12/12

Drag & Drop 이벤트

  • dragenter()
    드롭 영역에 진입할 때로 preventDefault()를 호출할 필요가 없다.

  • dragover()
    드래그 중인 항목이 영역 위에 있을 때 브라우저의 기본 동작을 preventDefault()로 막고 사용자 정의 동작을 적용한다.

  • dragleave()
    드래그 중인 항목이 영역을 빠져나갈 때로, 추가적인 인터페이스 표시 등의 작업을 하려면 preventDefault()를 호출하지 않는다.

  • drop()
    파일이나 데이터를 해당 영역으로 드롭할 때 브라우저의 기본 처리를 막고 사용자 정의 동작을 적용하기 위해 preventDefault()를 호출한다.

drop 이벤트가 두번 발생하는 문제를 해결하기 위해서는 상위요소로 해당 이벤트를 전달하지 않고 자신만 이벤트를 감지하도록 event.stopPropagation()을 사용해야 한다.

브라우저에 파일 업로드 및 미리보기

readAsDataURL(), createObjectURL 두 가지 모두 브라우저에서 로컬 파일을 읽을 때 사용하는 방법으로 파일 미리보기에 주로 사용된다.

readAsDataURL()로 구현

FileReader 객체를 통해 Blob, File 데이터를 base64 형식으로 읽어서 변환시킨다.
이 문자열을 <img>src에 넣어주면 된다.

pdf의 경우, PDF.js 라이브러리를 추가 사용해 구현 가능하다.

  • 이미지
public fileUpload(file: any) {
  const reader = new FileReader();
  const previewDiv = this.preview.nativeElement;
  if (file.type.match('image.*')) {
    reader.onload = (event: ProgressEvent<FileReader>) => {
	const img = document.createElement('img');
	this.upload = event.target?.result as string;
	img.src = event.target?.result as string;
	img.alt = file.name;
	previewDiv.appendChild(img);
  }
  reader.readAsDataURL(file);
}
  • pdf
else if (file.type === 'application/pdf') {
  pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdn.jsdelivr.net/npm/pdfjs-dist@4.0.269/build/pdf.worker.mjs';
  
  reader.onload = (e: ProgressEvent<FileReader>) => {
	const typedarray = new Uint8Array(e.target?.result as ArrayBuffer);
	pdfjsLib.getDocument(typedarray).promise.then((pdf: any) => {
	  const totalPageCount = pdf.numPages;
	  for (let pageNumber = 1; pageNumber <= totalPageCount; pageNumber++) {
		pdf.getPage(pageNumber).then((page: any) => {
		  const canvas = document.createElement('canvas');
		  const context = canvas.getContext('2d');
		  const viewport = page.getViewport({ scale: 1 });
		  canvas.height = viewport.height;
		  canvas.width = viewport.width;
		  const renderContext = {
            canvasContext: context,
			viewport: viewport,
		  };
		  page.render(renderContext).promise.then(() => {
			previewDiv.appendChild(canvas);
		  });
		});
      }
	}).catch((error: any) => {
      console.error('Error rendering PDF: ', error);
    });
  }
  reader.readAsArrayBuffer(file);
}

createObjectURL()로 구현

createObjectURL() 메서드는 Blob 객체를 가지고 고유한 URL을 생성할 수 있다.
브라우저 창을 닫을 때까지 유지되고 그 전에 해제하기 위해서는 revokeObjectURL()을 호출해야 한다.

  • 이미지
public fileUpload(file: any) {
  const reader = new FileReader();
  const previewDiv = this.preview.nativeElement;
  if (file.type.match('image.*')) {
    const img = document.createElement('img');
    img.src = URL.createObjectURL(file);
    previewDiv.appendChild(img);
  }
  • pdf
else if (file.type === 'application/pdf') {
  ...
  const pdfUrl = URL.createObjectURL(file);
  pdfjsLib.getDocument(pdfUrl).promise.then((pdf: any) => {
    ...
  })
}
  • 메모리
    문자열을 사용하는 readAsDataURL() 메소드와 달리, 포인터를 사용하는 createObjectURL()은 메모리를 덜 사용한다.

  • 속도
    비동기식으로 작동하는 readAsDataURL() 메소드와 달리, createObjectURL()은 동기식으로 작동하며 즉시 임시 URL을 생성하고 blob에 바인딩한다.

참고한 블로그

https://dev-gorany.tistory.com/254
https://inpa.tistory.com/entry/%EB%93%9C%EB%9E%98%EA%B7%B8-%EC%95%A4-%EB%93%9C%EB%A1%AD-Drag-Drop-%EA%B8%B0%EB%8A%A5
https://velog.io/@kykim/readAsDataURL-vs-createObjectURL
https://cdn.jsdelivr.net/npm/pdfjs-dist@4.0.269/build/

0개의 댓글