35350

how to to fit an image on a trapezium html canvas which I drew using path

Question:

[I want to add another image over the laptop screen`var ctx = myCanvas.getContext('2d');

ctx.beginPath(); ctx.moveTo(13,28); ctx.lineTo(237,7); ctx.lineTo(285,105); ctx.lineTo(73,151); ctx.closePath(); ctx.lineWidth = 0.5; ctx.strokeStyle = 'blue'; ctx.stroke(); //ctx.clip(); //ctx.rotate(-20*Math.PI/180); var img = new Image; img.onload = function() { var width = img.width; var height = img.height; ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, myCanvas.width, myCanvas.height); } }; img.src = reader.result; `][1]

how do I skew the image to fit in the trapezium ctx that i have created

Answer1:

<h2>Why 2D API is 2D</h2>

The canvas 2D API is called a 2D API for a very good reason. It can only do 2D transformations.

<h3>Not 2D</h3>

The shape you have...

<a href="https://i.stack.imgur.com/EFGyu.png" rel="nofollow"><img alt="enter image description here" class="b-lazy" data-src="https://i.stack.imgur.com/EFGyu.png" data-original="https://i.stack.imgur.com/EFGyu.png" src="https://etrip.eimg.top/images/2019/05/07/timg.gif" /></a>

The above image annotates your shape. Lines A,C are not parallel.

<h3>2D best fit</h3>

The canvas 2D transformation can not fit a rectangle to that shape as it does not carry enough information to deal with the converging lines and how to scale the pixels as they converge.

The best you can do is an approximation

The next image bisects the shape using two lines. These lines will be used to create the transform that will best fit the shape using the 2D transformation.

<a href="https://i.stack.imgur.com/6NOV7.png" rel="nofollow"><img alt="enter image description here" class="b-lazy" data-src="https://i.stack.imgur.com/6NOV7.png" data-original="https://i.stack.imgur.com/6NOV7.png" src="https://etrip.eimg.top/images/2019/05/07/timg.gif" /></a>

We use the bisecting lines to define the x and y axis of the transform and use the length of each to determine the scale. The center point of the image is the center of one of the bisecting lines.

<a href="https://i.stack.imgur.com/31zo7.png" rel="nofollow"><img alt="enter image description here" class="b-lazy" data-src="https://i.stack.imgur.com/31zo7.png" data-original="https://i.stack.imgur.com/31zo7.png" src="https://etrip.eimg.top/images/2019/05/07/timg.gif" /></a>

<pre class="snippet-code-js lang-js prettyprint-override">const ctx = canvas.getContext("2d"); const path = [13, 28, 237, 7, 285, 105, 73, 151]; const imageURL = "https://upload.wikimedia.org/wikipedia/commons/thumb/5/55/Sarcoramphus_papa_%28K%C3%B6nigsgeier_-_King_Vulture%29_-_Weltvogelpark_Walsrode_2013-01.jpg/675px-Sarcoramphus_papa_%28K%C3%B6nigsgeier_-_King_Vulture%29_-_Weltvogelpark_Walsrode_2013-01.jpg"; function setStyle(style){ Object.keys(style).forEach(key => ctx[key] = style[key]); } function drawPath(path, style) { var i = 0; setStyle(style); ctx.beginPath(); ctx.moveTo(path[i++], path[i++]); while (i < path.length) { ctx.lineTo(path[i++], path[i++]); } ctx.closePath(); ctx.stroke(); } function markPath(path, style, marks) { var i = 0; var len = path.length; setStyle(style); while (i < len) { ctx.fillText( marks[i >> 1], (path[i] + path[((i++) + 2) % len]) / 2, (path[i] + path[((i++) + 2) % len]) / 2 ); } } function bisectPath(path, modulo, style) { var i = 0; var len = path.length; setStyle(style); ctx.beginPath(); while (i < len) { ctx.moveTo( (path[i] + path[((i++) + 2) % len]) / 2, (path[i] + path[((i++) + 2) % len]) / 2 ); i += modulo; ctx.lineTo( (path[i] + path[((i++) + 2) % len]) / 2, (path[i] + path[((i++) + 2) % len]) / 2 ); i -= modulo + 2; } ctx.stroke(); } // functions to create lines, get vectors, length and normals function getLine(x1,y1,x2,y2){ return { p1 : { x : x1 , y : y1 }, p2 : { x : x2 , y : y2 } }; } function getVec(line){ line.vec = { x : line.p2.x - line.p1.x, y : line.p2.y - line.p1.y }; return line; } function getNormal(line){ line.len = Math.hypot(line.vec.x, line.vec.y); line.norm = { x : line.vec.x / line.len, y : line.vec.y / line.len, }; return line; } // create the 2 bisecting lines var line1 = getNormal( getVec( getLine( (path[0] + path[2]) / 2, (path[1] + path[3]) / 2, (path[4] + path[6]) / 2, (path[5] + path[7]) / 2 ))); var line2 = getNormal( getVec( getLine( (path[6] + path[0]) / 2, (path[7] + path[1]) / 2, (path[2] + path[4]) / 2, (path[3] + path[5]) / 2 ))); // create an image to fit var image = new Image; image.src = imageURL; image.onload = function(){ var w, h, sx, sy, cx, cy; w = this.width; h = this.height; // calculate the image scales sx = line2.len / w; sy = line1.len / h; // calculate the center cx = (line1.p1.x + line1.p2.x) / 2; cy = (line1.p1.y + line1.p2.y) / 2; // now we have all the information needed to create the transformation ctx.setTransform( line2.norm.x * sx, // scale and direction of x axis line2.norm.y * sx, line1.norm.x * sy, // scale and direction of y axis line1.norm.y * sy, cx, cy, // the origin coordinate (0,0) ); // Draw the image offset from its center by half its width and heigth ctx.drawImage(this, -w / 2, -h / 2); // reset the transformation ctx.setTransform(1,0,0,1,0,0); // draw the guides drawPath(path, { lineWidth : 0.5, strokeStyle : "blue" }); bisectPath(path, 2, { lineWidth : 1, strokeStyle : "white" }); markPath(path, { font : "18px arial", textAlign : "center", textBaseline : "middle", fillStyle : "black" }, ["A", "B", "C", "D"]); } <pre class="snippet-code-html lang-html prettyprint-override"><canvas id=canvas height=160></canvas>

That is the best you can do with the canvas 2D API. You could render each pixel calculating the 3D transform to fit the shape you have. Depending on the image size that can take some time (CPU) to do and the result will be OK.

<h3>WebGL for 3D</h3>

If you really need the 3D transform you should use webGL. There are plenty of examples on SO and the web on how to do that

Recommend

  • Distance (in px) between two elements in the DOM
  • Image expands the table cell
  • Inter change blue and red channels in bitmap in android
  • How do I convert image to 2-bit per pixel?
  • MATLAB: The exact size and position of the axis box in the case of `axis equal`?
  • dynamic EditText different size in different resolutions
  • How to add texture (image) to SceneKit model so that it covers the model (mesh) uniformly?
  • Find char width in pixels for various Arial fontsizes
  • how to set hue value of some pixel with opencv
  • Making a gif from images
  • Building tree/graph from image points
  • How to accurately measure mouse movement in inches or centimetres for a mouse with a known DPI
  • How can I add a python's ggplot object to a matplot grid?
  • Webpage with wide iframe is not scrollable on an iPhone with viewport
  • iOS Safari image rendering issue
  • How do I add margin between divs that are set to display table-cell?
  • How do I make a SKSpriteNode that does not respond to touch if it's pixels are transparent?
  • Restrict mouse movement over a specified window handle
  • onpreviewframe byte[] to int[]
  • Many to Many in Linq using Dapper
  • How can I prevent the need to copy strings passed to a avr-gcc C++ constructor?
  • cell spacing in div table
  • WPF version of .ScaleControl?
  • blade.php method outputting it's result to the form
  • Combining two different ActiveRecord collections into one
  • Java color detection
  • D3 get axis values on zoom event
  • R - Combining Columns to String Based on Logical Match
  • Read text file and split every line in MSBuild
  • DirectX11 ClearRenderTargetViewback with transparent buffer?
  • Fill an image in a square container while keeping aspect ratio
  • Why is the timeout on a windows udp receive socket always 500ms longer than set by SO_RCVTIMEO?
  • Web-crawler for facebook in python
  • Google cloud sdk not working when python points python3
  • Return words with double consecutive letters
  • how to add data labels for bar graph in matlab
  • Unit Testing MVC Web Application in Visual Studio and Problem with QTAgent
  • Error creating VM instance in Google Compute Engine
  • Hits per day in Google Big Query
  • how does django model after text[] in postgresql [duplicate]