简体   繁体   中英

how to draw contour around text image

How can i generate outline effect on text image in java script?

The closest solution on StackOverflow I found is How to add stroke/outline to transparent PNG image in JavaScript canvas

I have tried this code but it is working fine in any shape在此处输入图片说明 But my requirement is to draw outline like below images for example在此处输入图片说明

 // canvas related variables var canvas = document.getElementById("canvas"); // canvas.width = 600; // canvas.height = 400; var ctx = canvas.getContext("2d"); // variables used in pixel manipulation var canvases = []; var imageData, data, imageData1, data1; // size of sticker outline var strokeWeight = 8; // true/false function used by the edge detection method var defineNonTransparent = function(x, y) { return (data1[(y * cw + x) * 4 + 3] > 0); } var img = new Image(); document.querySelector('#fileinput').addEventListener('change', function() { var file = this.files[0]; var reader = new FileReader(); reader.onload = function(event) { let innerImageURL = event.target.result; console.log(innerImageURL); img = new Image(); img.crossOrigin = "anonymous"; img.onload = start; img.src = innerImageURL; // img.src = "https://cdn.glitch.com/c3106e6c-98cb-40e4-b0c1-85257680d25a%2Fsun.png?v=1564472507237"; }; reader.readAsDataURL(file); }); // the image receiving the sticker effect // var img = new Image(); // img.crossOrigin = "anonymous"; // img.onload = start; // img.src = "https://cdn.glitch.com/c3106e6c-98cb-40e4-b0c1-85257680d25a%2Fsun.png?v=1564472507237"; function start() { console.log(img.width) console.log(img.height) // resize the main canvas to the image size canvas.width = cw = img.width; canvas.height = ch = img.height; // draw the image on the main canvas ctx.drawImage(img, 0, 0); // Move every discrete element from the main canvas to a separate canvas // The sticker effect is applied individually to each discrete element and // is done on a separate canvas for each discrete element while (moveDiscreteElementToNewCanvas()) {} // add the sticker effect to all discrete elements (each canvas) for (var i = 0; i < canvases.length; i++) { addStickerEffect(canvases[i], strokeWeight); ctx.drawImage(canvases[i], 0, 0); } // redraw the original image // (necessary because the sticker effect // slightly intrudes on the discrete elements) ctx.drawImage(img, 0, 0); } // function addStickerEffect(canvas, strokeWeight) { var url = canvas.toDataURL(); var ctx1 = canvas.getContext("2d"); var pts = canvas.outlinePoints; addStickerLayer(ctx1, pts, strokeWeight); var imgx = new Image(); imgx.onload = function() { ctx1.drawImage(imgx, 0, 0); } imgx.src = url; } function addStickerLayer(context, points, weight) { imageData = context.getImageData(0, 0, canvas.width, canvas.height); data1 = imageData.data; var points = geom.contour(defineNonTransparent); defineGeomPath(context, points) context.lineJoin = "round"; context.lineCap = "round"; context.strokeStyle = "white"; context.lineWidth = weight; context.stroke(); } // This function finds discrete elements on the image // (discrete elements == a group of pixels not touching // another groups of pixels--eg each individual sprite on // a spritesheet is a discreet element) function moveDiscreteElementToNewCanvas() { // get the imageData of the main canvas imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); data1 = imageData.data; // test & return if the main canvas is empty // Note: do this b/ geom.contour will fatal-error if canvas is empty var hit = false; for (var i = 0; i < data1.length; i += 4) { if (data1[i + 3] > 0) { hit = true; break; } } if (!hit) { return; } // get the point-path that outlines a discrete element var points = geom.contour(defineNonTransparent); // create a new canvas and append it to page var newCanvas = document.createElement('canvas'); newCanvas.width = canvas.width; newCanvas.height = canvas.height; // newCanvas.style.display = "none"; document.body.appendChild(newCanvas); canvases.push(newCanvas); var newCtx = newCanvas.getContext('2d'); // attach the outline points to the new canvas (needed later) newCanvas.outlinePoints = points; // draw just that element to the new canvas defineGeomPath(newCtx, points); newCtx.save(); newCtx.clip(); newCtx.drawImage(canvas, 0, 0); newCtx.restore(); // remove the element from the main canvas defineGeomPath(ctx, points); ctx.save(); ctx.clip(); ctx.globalCompositeOperation = "destination-out"; ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.restore(); return (true); } // utility function // Defines a path on the canvas without stroking or filling that path function defineGeomPath(context, points) { context.beginPath(); context.moveTo(points[0][0], points[0][1]); for (var i = 1; i < points.length; i++) { context.lineTo(points[i][0], points[i][1]); } context.lineTo(points[0][0], points[0][1]); context.closePath(); } //////////////////////////// // Edge Detection /////////////////////////// (function() { geom = {}; geom.contour = function(grid, start) { var s = start || d3_geom_contourStart(grid), // starting point c = [], // contour polygon x = s[0], // current x position y = s[1], // current y position dx = 0, // next x direction dy = 0, // next y direction pdx = NaN, // previous x direction pdy = NaN, // previous y direction i = 0; do { // determine marching squares index i = 0; if (grid(x - 1, y - 1)) i += 1; if (grid(x, y - 1)) i += 2; if (grid(x - 1, y)) i += 4; if (grid(x, y)) i += 8; // determine next direction if (i === 6) { dx = pdy === -1 ? -1 : 1; dy = 0; } else if (i === 9) { dx = 0; dy = pdx === 1 ? -1 : 1; } else { dx = d3_geom_contourDx[i]; dy = d3_geom_contourDy[i]; } // update contour polygon if (dx != pdx && dy != pdy) { c.push([x, y]); pdx = dx; pdy = dy; } x += dx; y += dy; } while (s[0] != x || s[1] != y); return c; }; // lookup tables for marching directions var d3_geom_contourDx = [1, 0, 1, 1, -1, 0, -1, 1, 0, 0, 0, 0, -1, 0, -1, NaN], d3_geom_contourDy = [0, -1, 0, 0, 0, -1, 0, 0, 1, -1, 1, 1, 0, -1, 0, NaN]; function d3_geom_contourStart(grid) { var x = 0, y = 0; // search for a starting point; begin at origin // and proceed along outward-expanding diagonals while (true) { if (grid(x, y)) { return [x, y]; } if (x === 0) { x = y + 1; y = 0; } else { x = x - 1; y = y + 1; } } } })();
 #canvas { background: #f0f0f0; border-radius: 5px; } body { background-color: #333; color: #fff; display: flex; flex-direction: column; align-items: center; justify-content: center; font-family: Arial, Helvetica, sans-serif; min-height: 100vh; margin: 0; } * { box-sizing: border-box; } #source { display: none; }
 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=<device-width>, initial-scale=1.0"> <title>Document</title> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"></script> <link rel='stylesheet' href='https://code.getmdl.io/1.3.0/material.indigo-pink.min.css'> </head> <body> <div class='mdl-grid'> <div class='mdl-cell mdl-cell--4-col'> <label id='buttonUpload' for='fileinput' class='mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect mdl-button--accent'> <input type='file' id='fileinput' style='display: none'> Upload </label> <div class='mdl-tooltip' for='buttonUpload'> Upload the image to put inside the marker </div> </div> </div> <!-- <h4>Original Image</h4> --> <!-- <img height="200px" width="200px" src="https://cdn.glitch.com/c3106e6c-98cb-40e4-b0c1-85257680d25a%2Fsun.png?v=1564472507237"> --> <h4>Canvas with sticker effect applied</h4> <div class="container"> <canvas id="canvas" width="600" height="400"></canvas><br> </div> <h4>Each discrete element of the image is processed on a separate canvas<br>Temp-canvases are shown below for illustration purposes only.</h4> </body> </html>

I was thinking about how to get something close to what you show in your image:

Maybe if we draw the image offset at different angles we can get something close to that:

 var s = 16, x = 25, y = 25; var ctx = document.getElementById('canvas1').getContext('2d') var img = new Image; img.onload = draw1; img.src = "https://imgur.com/download/oXfw9nD/"; function draw1() { for (i = 0; i < 360; i++) ctx.drawImage(img, x + Math.sin(i) * s, y + Math.cos(i) * s); ctx.filter = 'invert(100)' ctx.drawImage(img, x, y); }
 <canvas id=canvas1 width=460 height=160></canvas>


You can also add some blur to soften the edges, take a look:

 var s = 6, x = 25, y = 25; var ctx = document.getElementById('canvas1').getContext('2d') var img = new Image; img.onload = draw1; img.src = "https://imgur.com/download/oXfw9nD/"; function draw1() { ctx.filter = 'blur(5px)' for (i = 0; i < 360; i++) ctx.drawImage(img, x + Math.sin(i) * s, y + Math.cos(i) * s); ctx.globalCompositeOperation = "source-in"; ctx.filter = 'invert(100)' ctx.globalCompositeOperation = "source-over"; ctx.drawImage(img, x, y); }
 <canvas id=canvas1 width=460 height=160></canvas>

That should get you closer to what you need

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM