캔버스에 그린 이미지를 PNG 이미지로 저장하는 방법이 필요해 찾아봤다. 평소에 구현해본게 아니라서 약간의 삽질이 있었지만 파일 구조를 좀 알고 있다면 그다지 어려운 일은 아니다. 참고로 본 설명은 Windows8 스토어 앱 개발에 필요했던 작업이라 WinJS 기준으로 설명하겠지만, 기본 원리는 다른 플랫폼이라도 동일할 것으로 생각된다.
1. 캔버스(Canvas)에 여러장의 이미지 로드하기
먼저 canvas를 이용해 이미지를 올려보자. HTML에 <canvas> 태그를 삽입하고 다음과 같은 코드를 이용해 이미지를 로드해본다.
var canvas = document.getElementById('canvas'); var cx = canvas.getContext('2d'); var imageObj = new Image(); imageObj.onload = function () { cx.drawImage(imageObj, 69, 50); } imageObj.src = 'http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg'; document.getElementById('save').onclick = function () { saveToFile('test.png'); } document.getElementById('load').onclick = function () { loadFromFile("test.png"); }
2. 캔버스 이미지 데이터 뽑아내기
이제 저장하기 버튼을 눌러서 캔버스에 그린 녀석들을 PNG 파일로 저장해보자. 저장할때는 캔버스에 있는 .toDataURL(‘image/png’) 이라는 메소드를 사용한다. 단, 원격지에 있는 이미지를 로드한 경우 보안 문제로 인해 다음과 같은 에러 메시지를 출력할 것이다.
Error: SECURITY_ERR: DOM Exception 18
따라서 .toDataURL() 메소드를 사용하려면 캔버스에 로드된 파일이 반드시 로컬에 위치해 있어야한다. 여튼 이 메소드는 캔버스의 픽셀 이미지를 Base64로 인코딩해서 다음과 같은 형태의 문자열 데이터로 출력해준다.
"data:image/png;base64,iVBORw0KGgoAAAANSuhEUgAAArwAAAH0......"
참고로 이 값을 이미지 태그의 src 주소에 넣으면 바로 이미지가 로드된다. 하지만 파일로 저장하려면 약간의 트릭이 필요하다. 먼저 PNG 데이터를 끄집어 내야한다.
3. PNG 이미지 데이터로 Blob 데이터 파일 만들기
PNG 파일에는 실제 이미지 데이터가 저장되어야 하기때문에 toDataURL() 로 출력된 문자열에서 “data:image/png;base64,” 이후로 나열된 문자열을 다시 디코딩해서 저장한다. 이런 이미지 데이터를 블럽(Blob) 데이터라고 얘기한다. WinJS의 경우 다음과 같은 메소드를 이용해 디코딩할수있다.
Windows.Security.Cryptography.CryptographicBuffer.decodeFromBase64String(인코드데이터)
파일로 저장하기위한 전체 메소드는 다음과 같이 작성했다. localFolder 객체는 앱 안에 저장되는 위치다.
var saveToFile = function (path) { var canvas = document.getElementById('canvas'), data = canvas.toDataURL('image/png'), localFolder = Windows.Storage.ApplicationData.current.localFolder, encodeData = data.replace("data:image/png;base64,", ""), decode = Windows.Security.Cryptography.CryptographicBuffer.decodeFromBase64String(encodeData); // mySample.txt의 이름으로 파일을 생성하고 동일한 이름이 있을 경우, 덮어쓴다. localFolder.createFileAsync(path, Windows.Storage.CreationCollisionOption.replaceExisting) .then(function (file) { // writeTextAsync메소들 통해 파일에 텍스트를 쓴다. return Windows.Storage.FileIO.writeBufferAsync(file, decode); }); };
4. 이미지 파일 로드하기
서두에도 잠깐 언급했지만, 이미지 파일을 로드는 간단하다. 그냥 이미지 파일 패스를 이미지 태그의 src 주소로 넣으면 끝이다. 일단 localFolder에 저장했으므로 localFolder에서 이미지 패스를 구해서 넣으면 끝! 코드는 아래와 같다.
var loadFromImage = function (path) { var localFolder = Windows.Storage.ApplicationData.current.localFolder; localFolder.getFileAsync(path).done(function (file) { var elTest = document.getElementById('test'), img = new Image(); img.src = URL.createObjectURL(file); elTest.appendChild(img); }); };