Good day, dear chabrozhiteli.<h2>Source image</h2> <div class="row"> <div class="source-image-area-out"> <!-- ( ) --> <div id="source-image-area"> Drop source image here... </div> </div> </div> <div class="row"> <!-- --> <label for="source-image-file" style="width: 150px">Or select this here:</label> <input type="file" id="source-image-file" /> </div> <h2>Settings</h2> <div class="left"> <!-- --> <div class="row"> <label for="input-used-text">Used text:</label> <input type="text" id="input-used-text" value="B" /> </div> <!-- --> <div class="row"> <label for="input-font-size">Font size:</label> <input type="number" id="input-font-size" min="3" max="20" step="1" value="8" style="width: 65px" /> px </div> </div> <div class="right"> <!-- --> <div class="row"> <label for="input-background-color">Background:</label> <input type="color" id="input-background-color" /> </div> <!-- --> <div class="row"> <label for="input-background-transparent">Transparent:</label> <input type="checkbox" id="input-background-transparent" /> </div> </div> <h2>Previews</h2> <!-- --> <div id="preview-result" class="left"> <img src="" id="image-result" alt="" /> </div> <!-- --> <div id="preview-source" class="right"> <img src="" id="image-source" alt="" /> </div> FileReader class. Its readAsDataURL() method returns the contents of the file as a data: URL scheme. Well, let's try. // , . var fileData = null; // . var loadFromField = function(event) { loadFile(event.target.files[0]; }; // “ ”. var loadFromArea = function(event) { event.stopPropagation(); event.preventDefault(); loadFile(event.dataTransfer.files[0]); }; // dragover “ ”. var areaDragOverHandler = function(event) { event.stopPropagation(); event.preventDefault(); event.dataTransfer.dropEffect = "copy"; }; // . // fileData. var loadFile = function(file) { var reader = new FileReader(); reader.onload = function(data) { fileData = data.target.result; } reader.readAsDataURL(file); } // . // document.getElementById("source-image-file").addEventListener("change", loadFromField, false); // “ ”. document.getElementById("source-image-area").addEventListener("drop", loadFromArea, false); document.getElementById("source-image-area").addeventListener("dragover", areaDragOverHandler, false); src attribute value for an image. So let's show the user the original image. var sourceImage = document.getElementById("mage-source"); sourceImage.src = fileData; var usedText = document.getElementById("input-used-text").value; var fontSize = document.getElementById("input-font-size").value; var backgroundColor = (document.getElementById("input-background-transparent").checked == true) ? "rgba(0,0,0,0)" : document.getElementById("input.background-color").value; <canvas id="canvas"></canvas> var canvas = document.getElementById("canvas"); var context = canvas.getContext("2d"); canvas.width = sourceImage.width; canvas.height = sourceImage.height; context.drawImage(sourceImage, 0, 0); var sourseData = context.getImageData(0, 0, canvas.width, canvas.height).data; getImageData() method returns canvas information. The data field contains a description of each pixel, just what we need. var getPixelsGrid = function(source) { var res = []; for (var i = 0; i < source.length; i += 4) { var y = Math.floor(i / (canvas.width * 4)); var x = (i - (y * canvas.height * 4)) / 4; if (typeof res[x] === "undefined") { res[x] = []; } res[x][y] = { r: source+0], g: source[i+1], b: source[i+2], a: source[i+3] } } return res; } var pixelsGrid = getPixelsGrid(sourseData); var countUsedTextSize = function(symbol, size) { var block = document.createElement("span"); block.innerHTML = symbol; block.style.fontSize = size + "px"; block.style.fontFamily = "Monospace"; document.body.appendChild(block); var re = [(block.offsetWidth, Math.floor(block.offsetHeight * 0.8)] document.body.removeChild(block); return re; }; // , . var size = countUsedTextSize(usedText[0], fontSize); var usedTextWidth = size[0] var usedTextHeight[1];
The attentive reader most likely noticed that not all the height of the symbol is taken into account, but only 80%. This is done because the visible part of the letter does not occupy the entire height it takes. Because of this, empty horizontal lines between the lines appear on the final image. They are especially noticeable if the letters are large. I adjusted, so that with different font sizes the distance between the lines was minimal - it turned out 80%. So leave. var getAvgPixelsList = function(grid) { var res = []; var stepX = usedTextWidth; var stepY = usedTextHeight; var countStepsX = canvas.width / stepX; var countStepsY = canvas.height / stepY; for (var y = 0; y < countStepsY; y++) { for (var x = 0; x < countStepsX; x++) { res.push({ x: x * stepX, y: y * stepY, r: grid[x * stepX][y * stepY].r, g: grid[x * stepX][y * stepY].g, b: grid[x * stepX][y * stepY].b, a: grid[x * stepX][y * stepY].a }); } } return res; }; var avgPixelsList = getAvgPixelsList(pixelsGrid); var nextUsedChart = 0; var getNextUsedChart = function() { var re = usedText.substring(nextUsedChart, nextUsedChart+1); nextUsedChart++; if(nextUsedChart == str.length) { nextUsedChart = 0; } return re; }; var getResultData = function(list) { // . context.clearRect(0, 0, canvas.width, canvas.height); context.fillStyle = backgroundColor; context.fillRect(0, 0, canvas.width, canvas.height); // . for (var i = 0; i < list.length; i++) { var px = list[i]; context.fillStyle = "rgba(" + px.r +", " + px.g + ", " + px.b + ", " + px.a + ")"; context.font = fontSize + "px Monospace"; context.fillText(getNextUsedChart(), px.x, px.y); } return canvas.toDataURL(); }; var resultData = getResultData(avgPixelsList); var resultImage = document.getElementById("image-result"); resultimage.src = resultData; 





Source: https://habr.com/ru/post/182782/
All Articles