1. 程式人生 > 其它 >圖片轉字元畫

圖片轉字元畫

一個有趣的程式。

主要技術包含圖片拖拽、貼上、雙擊上傳,然後通過canvas獲得圖片每一畫素的rgb顏色值,然後按顏色值總體大小使用相應的字元代替形成字元畫。

原圖:

轉換後:

程式碼:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>image2char</title>
    <style>
	.imageUploader {}
	.imageUploader .eventContainerDiv {width:100%;height:100px;min-width:300px;min-height:100px;border:3px dashed silver;padding:4px;cursor:default;}
	.imageUploader .eventContainerDiv img {display:none;overflow-x:auto;}
	.imageUploader .imageContainerDiv .imageBox {width:200px;height:150px;float:left;margin:4px;border:1px solid #eee;}
	.imageUploader .imageContainerDiv .imageBox img {max-width:100%;max-height:100%;object-fit: cover;}
	.imageUploader .imageContainerDiv .imageBox button {height:28px;margin-top:-28px;position: absolute;}
	.pixel-container {margin:0;padding:0;}
	.pixel-row {display:flex;}
	.pixel {width:12px;height:12px;margin:0;padding:0;font-size:12px;font-family:宋體;}
    </style>
</head>
<body>

<input type="hidden" id="article_link_image" name="article_link_image" value=""/>
<div id="imageUploader" class="imageUploader" upload="" maxWidth="400" maxHeight="600" limitCount="1"></div>
<div id="imageShow"></div>
</body>

<script>


    // 拖拽上傳,相容IE、FireFox、Chrome
    function dragEventProcess(eventContainerDiv,upload){
        document.addEventListener("dragenter", function(e){
            eventContainerDiv.style.borderColor = 'gray';
        }, false);
        document.addEventListener("dragleave", function(e){
            eventContainerDiv.style.borderColor = 'silver';
        }, false);
        eventContainerDiv.addEventListener("dragenter", function(e){
            eventContainerDiv.style.borderColor = 'gray';
            eventContainerDiv.style.backgroundColor = 'white';
        }, false);
        eventContainerDiv.addEventListener("dragleave", function(e){
            eventContainerDiv.style.backgroundColor = 'transparent';
        }, false);
        eventContainerDiv.addEventListener("dragenter", function(e){
            e.stopPropagation();
            e.preventDefault();
        }, false);
        eventContainerDiv.addEventListener("dragover", function(e){
            e.stopPropagation();
            e.preventDefault();
        }, false);
        eventContainerDiv.addEventListener("drop", function(e){
            e.stopPropagation();
            e.preventDefault();
			var imageFile = e.dataTransfer.files[0];
			loadImage(imageFile);
            //submit.disabled = false;
        }, false);
    }


    // 貼上上傳,相容IE、FireFox、Chrome
    function pasteEventProcess(eventContainerDiv,upload){
        eventContainerDiv.addEventListener("paste", function(event){
            // console.log(event);
            // console.log(clipboardData);
            // chrome、edge、firefox,不管貼上截圖還是網路圖片都能從clipboardData中得到圖片二進位制資料。
            if ( event.clipboardData || event.originalEvent ) {
                var clipboardData = (event.clipboardData || event.originalEvent.clipboardData);
                if ( clipboardData.items ) {
                    var  items = clipboardData.items;
                    for (var i = 0; i < items.length; i++) {
                        // console.log(items[i].type);
                        if (items[i].type.indexOf("image") !== -1) {
							var imageFile = items[i].getAsFile();
							loadImage(imageFile);
                        }
                    }

                }
            }else {
				alert('the browser is not support.');
            }
        }, false);
    }


    // 雙擊上傳
    function dblclickEventProcess(eventContainerDiv,upload){
        eventContainerDiv.addEventListener("dblclick", function(event){
            // 觸發上一個元素(input file)的點選事件
            eventContainerDiv.previousElementSibling.click();
        });
    }


    function clearEventContainerDivImages(eventContainerDiv){
        eventContainerDiv.setAttribute("count", "0");
        var images = eventContainerDiv.querySelectorAll("img");
        for(var i=0;i<images.length;i++){
            eventContainerDiv.removeChild(images[i]);
        }
    }

    // 初始化函式
    function initialize(){
        var imageUploaders = document.querySelectorAll(".imageUploader");
        if(imageUploaders && imageUploaders.length > 0){

            for(var i=0;i<imageUploaders.length;i++){
                var uploader = imageUploaders[i];
                // 如果已經初始化過則跳過。
                if(uploader.getAttribute("initialized") == "true") continue;
                
                var upload = uploader.getAttribute("upload");
                var eventContainerDiv = document.createElement("div");
                // 往div裡建立一個input file標籤,用於雙擊選擇檔案上傳
                var input = document.createElement("input");
                input.type = "file";
                input.style.display = "none";
                input.onchange = function(event){
                    var evt = window.event || event;
                    var evtsrc = evt.srcElement || evt.target;
                    //console.log(evtsrc.parentNode.id);
                    var imageFile = evtsrc.files[0];
                    loadImage(imageFile);
                };
                uploader.appendChild(input);

                // 往div裡建立兩個div,分別作為拖放貼上雙擊容器和圖片上傳後的呈現容器
                eventContainerDiv.className = "eventContainerDiv";
                eventContainerDiv.contentEditable = true;
                eventContainerDiv.innerHTML = "請將圖片貼上或拖拽到此區域,或雙擊此區域選擇圖片進行上傳.";


                // 繫結拖拽事件及處理
                dragEventProcess(eventContainerDiv,upload);
                // 繫結貼上事件及處理
                pasteEventProcess(eventContainerDiv,upload);
                // 繫結雙擊事件及處理
                dblclickEventProcess(eventContainerDiv,upload);
                // 新增到容器裡
                uploader.appendChild(eventContainerDiv);
                var imageContainerDiv = document.createElement("div");
                imageContainerDiv.className = "imageContainerDiv";

                // 新增到容器裡
                uploader.appendChild(imageContainerDiv);



                uploader.setAttribute("initialized", "true");

            }
        }
    }


    window.addEventListener("load",function(){
        // 在window下設定一個初始化函式,用於可動態地初始化元件(用js動態建立的元件,需要動態初始化)。
        window.powerfulImageUploadInitialize = initialize;
        powerfulImageUploadInitialize();
    },false);


  function group(array, subGroupLength) {
      let index = 0;
      let newArray = [];
      while(index < array.length) {
          newArray.push(array.slice(index, index += subGroupLength));
      }
      return newArray;
  }
  
	function loadImage(imageFile) {
		var canvas = document.createElement('canvas'); 
		var context = canvas.getContext('2d');
		var reader = new FileReader(); 
		reader.readAsDataURL(imageFile); 
		reader.onload = function(e){ // reader onload start 
		  var image = new Image(); 
		  image.src = e.target.result; 
		  image.onload = function(){ // image onload start 
			var img_width = this.width; 
			var img_height = this.height; 
			// 設定畫布尺寸 
			canvas.width = img_width; 
			canvas.height = img_height; 
			// 將圖片按畫素寫入畫布 
			context.drawImage(this, 0, 0, img_width, img_height); 
			// 讀取圖片畫素資訊 
			var imageData = context.getImageData(0, 0, img_width, img_height); 
			var colorRows = group(imageData.data, img_width * 4); // 每4個元素表示一個畫素的rgba。
			imageRGB2Char(colorRows);
		  }
		 
		}
	}
	
	function imageRGB2Char(colorRows) {
		var html = '';
		console.log('colorRows.length:', colorRows.length);
		for (var x=0; x<colorRows.length; x++) {
			html += '<div class="pixel-row">';
			var cells = colorRows[x];
			console.log('cells.length', cells.length);
			for (var y=0; y<cells.length; y++) {
				if(y%4 === 0){ // 每四個元素為一個畫素資料 r,g,b,alpha 
					// 這裡只取rgb,不取a
					var rgb = cells[y] + ',' + cells[y+1] + ',' + cells[y+2];
					// html += '<div class="pixel" style="background-color: rgb('+ rgb2char(rgb) +');"></div>';
					html += '<div class="pixel" style="color: rgb('+ rgb +');">' + rgb2char(rgb) + '</div>';
				} 
			}
			html += '</div>';
		}
		document.getElementById('imageShow').innerHTML = html;
	}
	
	function rgb2char(rgb) {
		rgb = eval(rgb.replaceAll(',', '+'));
		var charr = '';
		if (rgb >= 722) {
			charr = "  ";
		} else if (rgb >= 684 && rgb < 722) {
			charr = ";;";
		} else if (rgb >= 646 && rgb < 684) {
			charr = "\'\'";
		} else if (rgb >= 608 && rgb < 646) {
			charr = "..";
		} else if (rgb >= 570 && rgb < 608) {
			charr = ",,";
		} else if (rgb >= 532 && rgb < 570) {
			charr = "::";
		} else if (rgb >= 494 && rgb < 532) {
			charr = "tt";
		} else if (rgb >= 456 && rgb < 494) {
			charr = "rr";
		} else if (rgb >= 418 && rgb < 456) {
			charr = "ff";
		} else if (rgb >= 380 && rgb < 418) {
			charr = "kk";
		} else if (rgb >= 342 && rgb < 380) {
			charr = "ZZ";
		} else if (rgb >= 304 && rgb < 342) {
			charr = "FF";
		} else if (rgb >= 266 && rgb < 304) {
			charr = "XX";
		} else if (rgb >= 228 && rgb < 266) {
			charr = "##";
		} else if (rgb >= 190 && rgb < 228) {
			charr = "BB";
		} else if (rgb >= 152 && rgb < 190) {
			charr = "HH";
		} else if (rgb >= 114 && rgb < 152) {
			charr = "WW";
		} else if (rgb >= 76 && rgb < 114) {
			charr = "NN";
		} else if (rgb >= 38 && rgb < 76) {
			charr = "@@";
		} else if (rgb >= 0 && rgb < 38) {
			charr = "MM";
		}
		return charr;
	}
	
</script>
</html>