본문 바로가기

웹개발 관련

CKEditor4를 이용한 html 메타데이터 캔버스 구현

구현 방향

글상자안에서 작성이 끝나면 캔버스 이미지를 만들어서 썸네일 역할을 하려고한다.

 

구현

// Drawing DOM Objects into a canvas
function draw(target) {
    if (target.attributes[2] || target.attributes[3])
        target.setAttribute("width", 0)
        target.setAttribute("height", 0)

    const canvas = target;
    const dpr = window.devicePixelRatio;
    let ctx = canvas.getContext('2d');

    if (!ctx) 
        return

    const htmlMeta =  CKEDITOR.instances.introduction.getData()
    const data = `
                <svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="none">
                    <style> div { font-family: MalgunGothic; font-size: 14px; } table { table-layout: fixed; border-spacing: 0; border-collapse: collapse;} p { margin: 0 0 10px; }</style>
                    <foreignObject width="100%" height="100%">
                        <div xmlns="http://www.w3.org/1999/xhtml">
                            ${htmlMeta}
                        </div>
                    </foreignObject>    
                </svg>`;
    
    const DOMURL = window.URL || window.webkitURL || window;
    const img = new Image();
    const svg = new Blob([data], {type: 'image/svg+xml;charset=utf-8'});
    const url = DOMURL.createObjectURL(svg);

    ctx.canvas.style.border = (document.querySelector(`#${Object.getOwnPropertyNames(CKEDITOR.instances)[0]}`).style.border === '' ? 
    '1px hidden black' : document.querySelector(`#${Object.getOwnPropertyNames(CKEDITOR.instances)[0]}`).style.border)
    ctx.canvas.style.background = document.querySelector(`#${Object.getOwnPropertyNames(CKEDITOR.instances)[0]}`).style.background

    ctx.canvas.width = editingArea.offsetWidth * dpr
    ctx.canvas.height = editingArea.offsetHeight * dpr
    ctx.canvas.style.width = `${editingArea.offsetWidth}px` //css
    ctx.canvas.style.height = `${editingArea.offsetHeight}px`

    img.onerror = function () {
        console.log('That image was not loaded')
    }

    img.onload = function () {
        ctx.scale(dpr, dpr);
        ctx.drawImage(img, 0, 0, ctx.canvas.width, ctx.canvas.height)
        
        DOMURL.revokeObjectURL(url)
    }

    img.src = url
}

위 코드는 아래와 같은 단계를 거치고 있다.

  1. 캔버스 엘리먼트 및 id 선언
  2. 2d 컨버스 객체 그리기
  3. svg요소 + foreignObject요소 + editor에서 작성한 html 메타데이터 가져오기
  4. Blob(Binary Large Object)을 이용하여 이미지 생성
  5. URL.createObjectURL() 사용하여 DOMString 으로 변환
  6. url을 할당하고 이미지 로드 시 컨텍스트에 이미지 띄우기

구현 중 해상도가 높은 모니터에서 텍스트가 흐릿하게 보이는 현상(text blurry)이 발생했다.

Canvas 크기와 화면에 표시(디스플레이) 되는 크기는 다르며, 디스플레이 크기는 DPR의 영향을 받는다는 사실을 알게되었다.

DPR는 웹 브라우저에서 전역변수 window.devicePixelRatio 로 확인해볼 수 있는데, CSS 픽셀을 구성하는데 필요한 물리적 픽셀 수 를 의미한다.Canvas 요소의 width, height 속성을 DPR 배율로 계산해 주고 디스플레이 크기(CSS에서 지정해 준 width, height 값)와 맞춰주기 위해 scale을 조정 했다.

 

참고: https://meetup.toast.com/posts/297