본문 바로가기

FRONT/Vue.js

Vue3 - 동영상 url로 썸네일 직접 만들기... (Canvas/vue3/typescript)

들어가기 전..

 

하.. 이번에 동영상 썸네일 만들라고 하셔서 작업하는데.. 자꾸 canvas에 안그려져서 무척이나 당황스러웠다.아무튼 좌충우돌 해결해서 나중에 이런 작업이 또 생기면 보려고 기록차 글을 남깁니다.아직 하자가 있습니다. 비율이 깨진다는 하자요. 다음에 수정해야겠어요.

 


 

html (template)

	<div>
        <video
          ref="videoOriginElement"
          :src="setVideo"
          controls
          :width="canvas.width"
          :height="canvas.height"
          muted
          hidden
        />
        <canvas ref="videoThumbnailElement" :width="canvas.width" :height="canvas.height" />
    </div>

 

 

javascript (vue - typescript)

// ...중략

props: {
	file: {
      type: Object,
      required: true,
	},
    originFileList: {
      type: Array as PropType<File[]>,
    },
},
setup(props, {emit}) {
    const videoOriginElement = ref<HTMLVideoElement>();
    const videoThumbnailElement = ref<HTMLCanvasElement>();

    const state = reactive({
    	canvas : {
        	width: 80,
            height: 80,
        },
        canvasCtx: null as CanvasRenderingContext2D | null | undefined,
    });
    
    
	// video src 만들기
    const setVideo = computed(() => {
      // props에서 받은 file(필수!! required) 에서 url 꺼내기.
      let src = props.file.url ?? props.file.URL ?? '';


	  // or 이 방식은 input file 에서 받을 경우
      // originFileList = 저흰 multiple 이여서 파일 list 였음
      if (props.state === 'form' && props.originFileList) {
        let currentFile;

        props.originFileList.map((object: File) => {
          if (object.name === props.file.fileName) {
            currentFile = object;
          }
        });

        src = URL.createObjectURL(currentFile);
      }
      return src;
    });
    
    

    onMounted(async () => {
    	// fileType이 video인지 체크.
        // 저흰 video 말고도 이미지 등등 여러 포맷들을 다 받는데 동영상 일 경우 썸네일을 만드는거라 이럼;
      if (isVideo(props.file.url ?? props.file.FileName)) {
        await nextTick();
        
        // 이게 중요함 alpha option 없으니까 안만들어져서 대환장 파티였음. ㅂㄷ 이거땜에 하루 헤딩함 왜 안되나하고
        state.canvasCtx = videoThumbnailElement.value?.getContext('2d', {
          alpha: false,
        });
        setVideoImage();
      }
    });
    
    
	// 동영상 로드 되면 이래저래 만져주는 공간 
    // 사실 template video tag에 @loadedmetadata="함수"해서 작업했어도 될 것 같음
    function setVideoImage() {
      const video = videoOriginElement.value;
      const canvas = videoThumbnailElement.value;

      if (video && canvas) {
        video.addEventListener('loadedmetadata', async function () {
          //비디오의 영상길이 중 랜덤 타임을 뽑음
          // video.currentTime = Math.random() * video.duration; //해당 시간으로 이동
          video.currentTime = 1; //해당 시간으로 이동

          await video?.play();

          drawVideoThumbnail();
          requestAnimationFrame(drawVideoThumbnail);
          await video?.pause();
        });
      }
    }

	// canvas 에 그리는 것
    async function drawVideoThumbnail() {
      const video = videoOriginElement.value;
      const canvas = videoThumbnailElement.value;

      if (canvas && state.canvasCtx && video) {
        state.canvasCtx.drawImage(video, 0, 0, video.width, video.height);
      }
    }
    
    
    
    function isVideo(fileUrl) {
      const fileName = getExtension(fileUrl);
      switch (fileName.toLowerCase()) {
        case 'mp4':
        case 'mov':
          return true;
      }
      return false;
    }
    

    return {
      ...toRefs(state),
      videoOriginElement,
      videoThumbnailElement,
  	}

}

 

 예예.. 이리 해결은 했습니다.

다들 먼 유투브에서 따오거나 그래서.. 

저도 한 번 적어봤습니다

프론트 개발자 여러분 화이팅~!


다음에는 사용방법에 대하여 작성하겠습니다.

 

참고

https://shifeed.tistory.com/entry/%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8%EC%82%AC%EC%9A%A9%EC%9E%90%EC%AA%BD%EC%97%90%EC%84%9C-%EB%B9%84%EB%94%94%EC%98%A4-%EC%8D%B8%EB%84%A4%EC%9D%BC-%EB%BD%91%EA%B8%B0

https://stackoverflow.com/questions/40143958/javascript-generate-video-thumbnail-from-video-url

...등등

 

'FRONT > Vue.js' 카테고리의 다른 글

Vuex : Vue.js 상태관리 패턴 라이브러리 이해하기  (0) 2020.05.26