Vue 브라우저에서 heic 파일 핸들링하기(express)

정태호·2023년 3월 29일
0

[참고 사이트]Blob,Base64,File,Buffer에 대해서 설명

https://inpa.tistory.com/entry/JS-📚-Base64-Blob-ArrayBuffer-File-다루기-정말-이해하기-쉽게-설명


.heic 확장자를 가지는 이미지 url을 브라우저에서 랜더링하기 위한 과정을 작성한 내용입니다.

웹서버 → 브라우저 → 이미지 변환 → base64 url 과정을 거치기 때문에 이미지 랜더링까지 딜레이가 발생합니다.

express 웹서버를 통한 이미지 파일 전달하기

  • 브라우저에서는 CORS 정책으로 인해 javascript에서 fetch 메소드를 통해 데이터를 요구할 수 없습니다.

  • 이를 해결하기 위해

    1. 이미지 파일을 제공하는 서버의 CORS 정책을 수정하여 브라우저에서 직접 이미지를 수신
    2. 웹서버로 사용할 express를 통해 이미지를 요청

    • 디버깅 및 개발환경에서의 호출과 보안정책 수정의 리스크로 인해 express 서버를 통한 우회를 결정했습니다.
//vue에서 요청할 url과 일치시키기 위해 환경변수로 관리
app.get(process.env.VITE_IMAGE_URL,async(req,res,next)=>{
	try{
		const baseUrlLsit = ['처리할 baseurl을 지정']
		const query = req.query

		if(!query.uri || !baseUrlLsit.includes(query.uri.split('/').slice(0,3).join('/'))){
			return res.status(403).json(createError(403))
		}
		//node 18 버전 부터 fetch 함수가 추가되었습니다.
		const response = await fetch(query.uri)
		const blob = await response.blob()
		const arrayBuffer = await blob.arrayBuffer()

		res.writeHead(200,{ "Context-Type": "image/heic"})

		res.write(Buffer.from(arrayBuffer))
		res.end()
	}
	catch(error){
		next(error)
	}
})
  • express 서버에서 동일하게 fetch 함수를 사용하여 이미지를 요청합니다.

    • 이때 다른 도메인에 대한 파일 요청을 막기위해 특정 도메인 요청에 대해서만 처리되도록 합니다.
    • blob 타입의 데이터는 전송할 수 없기 때문에 buffer 타입의 데이터로 변경후 전송합니다.

VueJS(브라우저)에서 이미지 전달 받기

  • .heic 확장자의 이미지를 요청하는 url을 express에 전달하여 이미지 파일을 받습니다.
const getUrltoImage = async (url :string)=>{
	const baseUrl = import.meta.env.VITE_ENVIRONMENT === 'production'? '': import.meta.env.VITE_SERVER_URL
	
	const response = await fetch(baseUrl + import.meta.env.VITE_IMAGE_URL + `?uri=${url}`)
	const blob = await response.blob()
	const file = new File([blob as any],url.split('/').slice(-1)[0],{type:"image/heic"})

	return file
}
  • 이때에도 fetch 함수를 통해 데이터를 요청합니다.
    • (반환 타입에서 지원하는 blob() 함수를 사용하기 위해)
  • express 를 통해 전달받은 이미지 데이터를 File 타입으로 변환합니다.

.heic 확장자 이미지 → .jpeg 확장자 이미지로 변환하기

  • 브라우저에서는 .heic 확장자의 이미지를 지원하지 않습니다. 이를 다른 확장자의 이미지로 변경해야합니다.
import heic2any from'heic2any';

const getHeicToJpeg = async (file :File)=>{
	const JpegBlob = await heic2any({
		blob:file,
		toType: 'image/jpeg'
	})

	const name = file.name.split('.')[0] + '.jpeg'
	const newFile = new File([JpegBlob as any],name)

	return newFile
}
  • 변환을 위해서 heic2any 패키지를 사용합니다. npm i heic2any
    • 해당 패키지는 브라우저환경에서만 작동합니다. (license: MIT)
  • jpeg 확장자로 생성된 blob 타입을 다시 File 타입으로 변경하면 전환이 완료됩니다.
    • 이때 파일 이름의 확장자를 변경된 확장자명으로 변경하여 넣어줍니다.(아님 에러가 발생할 수 있음)
  • 이렇게 변경된 이미지 파일을 업로드 하거나 브라우저에서 보여줄수 있도록 base64의 url로 변경할 수 있습니다.

File 타입의 이미지 데이터를 base64 url로 변경하기

  • 브라우저에서 이미지데이터를 base64로 변경하는 방법으로 다음 함수를 사용했습니다.
    • (base 64 url 만드는 다른 함수가 존재하지만 포인터 관리를 해야하기 때문에 해당 함수를 사용)
      • new FileReader()
        const getBase64Url = async (file: File):Promise<string> =>new Promise((resolve,reject)=>{
        	const imageReader = new FileReader()
        
        	imageReader.onload = (e:any)=>{
        		if(e.target.result) resolve(e.target.result as string)
        		else reject("이미지 변환에 실패했습니다!")
        	}
        	imageReader.readAsDataURL(file)
        })
        • 해당 방식은 onload 훅에서 이미지 데이터를 직접 가지는 url 정보를 가져와 사용합니다.
        • 반환되는 string 타입의 정보를 img 태크에 src 속성 값으로 넣어주면 이미지가 랜더링됩니다.

0개의 댓글