활동 후기/텍스트 합성 사이트 프로젝트

텍스트 합성 사이트 프로젝트 <3 - 크기 및 위치 조정, 사진 추가>

문과 해달 2021. 8. 12. 01:57

이 프로젝트를 빠르게 해치우고 관두려 했는데, 2편을 쓴 시점부터 많은 날이 지났다.

그 이유는 일단 중간에 팀원과 Billboard hot 100 사이트 만들기를 진행했고,

그 도중에 파일을 혼동에 이 프로젝트의 html 파일을 날려 버렸기도 했기 때문이다...

 

따라서 오늘은 이전까지의 작업을 다시 복원하는 것으로 시작했다.

그 이후엔 저번에 발생한 다양한 문제들을 해결해보았다. 아래와 같다.

 

1. 텍스트의 길이에 따라 적절한 위치, 폰트 사이즈가 변화한다는 점

2. 줄바꿈을 적절히 해주는 기능이 없다는 점

3. 사진에 따라 폰트, 폰트 사이즈, 색, 위치 등을 바꿔줘야 하기에 사진마다 이 정보를 저장할

자료구조가 필요하다는 점

1. 폰트사이즈와 베이스라인 조정

먼저 1번 문제 해결에 착수했다. 가장 고민이었던 부분은 사용자가 form에 작성한 텍스트의 길이에 따라

동적으로 폰트크기를 조절할 아이디어의 부재였다.

하지만 MDN 의 캔버스 api 페이지를 읽다 measureText() (en-US)의 존재를 알게 되었다. measureText는 '현재 스타일로 특정 텍스트가 그려질 때의 폭, 픽셀 등을 포함하는 TextMetrics (en-US) 객체 리턴.'을 제공한다. 이 중에는 width 필드가 존재해, 특정 문자를 그렸을 때 실제 width를 미리 알 수 있다. 사용예는 다음과 같다.

function draw() {
  var ctx = document.getElementById('canvas').getContext('2d');
  var text = ctx.measureText('foo'); // TextMetrics object
  text.width; // 16;
}

 이를 활용해 js에서 while문을 돌려 이 width값이 특정 값보다 작아질 때까지 font-size를 줄여주었다.

let fsize = start_size;
let text = document.querySelector('.text').value;
while (true) {
cont.font = fsize + 'pt ' + font_family;

if (cont.measureText(text).width < max_width) break
else fsize -= 1;
}

따라서 텍스트는 길이에 맞게 font-size가 감소해서 항상 정해진 영역에 표시될 수 있게 되었다.

텍스트가 짧을 때와 길 때

크기에 따라 적히는 위치가 달라지는 것도 문제였는데, canvas에서 textBaseline 속성을 통해 이를 고칠 수도 있었다.

cont.textBaseline = 'middle';

생각보다 canvas가 제공하는 텍스트 그리기가 디테일해, 고칠수 있을까 싶던 문제들을 쉽게 고쳤다.

 

하지만 2번 문제 줄 바꿈을 구현할 방법은 정말 없는 것 같다. 만일 정말 필요하다면

input을 추가로 받아서 일일히 구현해 주어야 할 듯 하다.

 

2. 이미지 클래스화 및 사진 추가

추가로 사진을 사용하려면 그에 따라 적절히 여러 설정들이 바꾼 후 텍스트를 그려줘야만 한다.

이를 관리하기 위해 장고 상에서 Model을 작성해, 객체화해주었다.

class 명에 보통 s를 붙여주던가, 반대던가. 항상 헷갈린다.

class Images(models.Model):
    img_url = models.CharField(max_length=400) //배경 이미지의 url
    posx = models.CharField(max_length=100) //x좌표
    posy = models.CharField(max_length=100) //y좌표
    start_size = models.CharField(max_length=100) //폰트의 최대 크기
    max_width = models.CharField(max_length=100) //텍스트를 쓸 수 있는 영역의 크기
    font_family = models.CharField(max_length=100) //폰트 종류
    rotate = models.CharField(max_length=100) // 텍스트의 기울기
    color = models.CharField(max_length=100) // 텍스트 색깔
    alpha = models.CharField(max_length=100) // 텍스트 투명도

페이지를 나누기 위해 url도 id에 따라 분화시켜 주었고, view 함수에서 Image 객체를 넘겨 주도록 했다.

객체 생성은 admin 페이지에서 직접 했다. 사용자가 생성할 일이 없기에, 객체를 만드는 페이지나 기능은 없다.

admin 페이지에서 직접 객체 생성/수정

이제 객체에 맞게 정보들을 받아와 작동하도록 만들어야 한다.

let img = new Image();
img.src = "{% static '파일이름' %}";

cont.drawImage(img,0,0,757,440);

문제는 위와 같이 이미지 객체를 만들어 소스를 지정해주고 그려내야 하는데, 파일이름 자리에 변수가 들어가야 한다는 점이다. 문자열 합치기를 하려 온갖 방법을 시도해보았지만, 제대로 인식하지 못했다.

브라우저의 검사 탭에서 source를 확인해보니 장고의 "{% static '파일이름'%}" 문법이 브라우저에선

"static/파일이름"으로 바뀌는 것을 알 수 있었다. 이에 맞춰

let img = new Image();
const imgurl = '{{info.img_url}}';
let txt = "/static/"+imgurl;
img.src = txt
cont.drawImage(img,0,0,757,440);

다음과 같이 문자열 합치기를 해서 src를 지정해주었다..... 더욱 쉬운 방법은 없으려나

 

다른 사진 업로드

아무튼 이제 url을 옮겨 다른 사진이 배경인 페이지를 켤 수 있게 되었다.

이전 사진에서 해준 것 같이 적절한 폰트, 사이즈, 위치, 영역 너비, 투명도 등을 찾아 객체를 생성해주었다.

두 번째 사진도 완성. 뭔가 칠판 구석구석에 자연스러운 흔적들이 있었으면 더 좋을 것 같다.

바로 세 번째 사진 만들기 착수. 첫 번째와 두 번째는 엄청 평면에 손글씨 느낌이었으니,

다른 느낌으로 찾아보려 했다. pexels에서 옥외 광고판 사진을 찾아 포토샵에서 글씨를 지우고

기울기를 적절히 주어 광고 문구 느낌을 주려했다.

세 번째 사진

이 사진의 경우 미세한 기울기를 정확히 맞춰줘야 합성 티가 잘 안나는데,

텍스트 길이마다 기울기 체감이 조금 나서 어렵다.

한 줄만 텍스트가 있는 것도 아무래도 부족해 보여서 input을 여러 줄 두어 여러 줄로 구현할까 하는 생각도 있다.

 

지금까지가 현재 진행 상태이다. 앞으로의 계획은, 위에 말한 듯 세 번째 사진의 퀄리티를 더 높이거나

더 어렵게 합성할 필요가 있는 다음 사진을 찾아 추가할 듯 하다.