简体   繁体   English

Canvas 线性渐变取另一个输入类型颜色字段的值

[英]Canvas linear gradient taking the value of another input type color field

So I have this simple image editor where I'm using a canvas to draw in a user-selected image and some texts.所以我有这个简单的图像编辑器,我使用 canvas 来绘制用户选择的图像和一些文本。 That is the user can upload an image and then if they want they can add texts or just change the gradient of the image.也就是说,用户可以上传图像,然后如果他们愿意,他们可以添加文本或只是更改图像的渐变。

Right now the app works perfectly fine except there is one issue.现在该应用程序运行良好,除了有一个问题。

How to find the issue?如何找到问题? Do the following:请执行下列操作:

  1. Upload a random image.上传随机图片。
  2. Choose a color from Text 2 Shadow Offset X Color Picker.Text 2 Shadow Offset X Color Picker 中选择一种颜色。
  3. Increase the slider beside the Text 2 Shadow Offset X Color Picker.Text 2 Shadow Offset X Color Picker旁边增加slider。
  4. Then increase the slider of Image Gradient and Opacity .然后增加Image Gradient and Opacity的 slider 。

The image will have a gradient and take the value of the Text 2 Shadow Offset X Color Picker instead of Image Gradient and Opacity Color Picker which has default black color.图像将具有渐变并采用Text 2 Shadow Offset X Color Picker 的值,而不是具有默认黑色的Image Gradient and Opacity Color Picker 的值。

This is the code:这是代码:

 const canvasTxt = window.canvasTxt.default; const canvas = document.getElementById('canvas'); const ctx = canvas?.getContext('2d'); const btnDownload = document.querySelector('.btnDownload'); const fileUpload = document.querySelector('.file-upload'); const text1 = document.getElementById('text1'); const textForm1 = document.getElementById('text1-form'); const text2 = document.getElementById('text2'); const textForm2 = document.getElementById('text2-form'); const text2ShadowColor = document.getElementById('text2shadowcolor'); const text2ShadowOffsetY = document.getElementById('text2shadowoffy'); const imageForm = document.getElementById('image-form'); const imageGrad = document.getElementById('gradientcolor'); const imageGradOpacity = document.getElementById('gradientopacity'); $(fileUpload).on('change', function(e) { let imgObj = new Image(); imgObj.onload = draw; imgObj.onerror = failed; imgObj.src = URL.createObjectURL(this.files[0]); imgManipulation( e, imgObj ); }); const imgManipulation = ( e, imgObj ) => { $(textForm1).on('change keyup input', updateCanvas); $(textForm2).on('change keyup input', updateCanvas); $(imageForm).on('change keyup input', updateCanvas); function updateCanvas(e) { e.preventDefault(); ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.drawImage(imgObj, 0, 0); createGradient($(imageGrad).val(), $(imageGradOpacity).val()); // TEXT1 STYLES based on user input canvasTxt.fontSize = 30; canvasTxt.drawText( ctx, $(text1).val(), 0, 0, 200, 200 ); // TEXT2 STYLES canvasTxt.font = 20; canvasTxt.drawText( ctx, $(text2).val(), 20, 20, 200, 200 ); } }; function hexToRgb(hex) { var result = /^#?([af\d]{2})([af\d]{2})([af\d]{2})$/i.exec(hex); return result? { r: parseInt(result[1], 16), g: parseInt(result[2], 16), b: parseInt(result[3], 16) }: null; }; function createGradient(hex, alpha) { const r = hexToRgb(hex).r.toString(); const g = hexToRgb(hex).g.toString(); const b = hexToRgb(hex).b.toString(); var gradient = ctx.createLinearGradient(800, 0, 0, 0); gradient.addColorStop(0, `rgba(${r}, ${g}, ${b}, ${alpha})`); ctx.save() // <----------- ADD ctx.fillStyle = gradient; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.restore() // <----------- ADD }; function draw() { canvas.width = this.naturalWidth; canvas.height = this.naturalHeight; const nw = this.naturalWidth; const nh = this.naturalHeight; ctx.drawImage(this, 0, 0, nw, nh); }; function failed() { console.error("The provided file couldn't be loaded as an Image media"); }; $(btnDownload).on('click', function(e) { const a = document.createElement('a'); document.body.appendChild(a); a.href = canvas.toDataURL(); a.download = "canvas-image.png"; a.click(); document.body.removeChild(a); });
 #canvas{ background-color: transparent; width: 30%; height: auto; border: 1px solid #777; }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script> <script src="https://unpkg.com/canvas-txt@3.0.0/build/index.js"></script> <canvas id="canvas" width="800" height="500"></canvas> <div> <input type="file" class="file-upload" /> <button class="btnDownload">Download</button> </div> <div> <form id="text1-form"> <input type="text" id="text1" placeholder="text 1"/> </form> </div> <div> <form id="text2-form"> <input type="text" id="text2" placeholder="text 2"/> </form> </div> <div> <h2>Image Gradient and Opacity</h2> <form id="image-form"> <input type="color" id="gradientcolor" value="#000000" /> <input type="range" id="gradientopacity" min="0" max="1" value="0" step="0.05" /> </form> </div> <div> <h2>Text2 Shadow Offset X</h2> <input type="color" id="text2shadowcolor" value="#000000" /> <input type="range" id="text2shadowoffy" min="0" max="40" value="0" /> </div>

Rundown of the code:代码概要:

1: First I have the fileUpload event listener. 1:首先我有fileUpload事件监听器。 It takes in an image from the user and creates an image object and draws it on the canvas.它从用户那里获取图像并创建图像 object 并将其绘制在 canvas 上。 Then imgManipulation function is called with the imgObj and event as its arguments.然后imgManipulation function 并使用imgObjevent作为其 arguments。

  1. The imgManipulation function starts off with the input event listeners for the texts. imgManipulation function 从文本的input事件侦听器开始。 That is whenever there is a change in the input, that is a user writes something, updateCanvas function is called.也就是说,只要输入发生变化,即用户写了一些东西,就会调用updateCanvas function。

  2. The updateCanvas function actually draws the texts on the image. updateCanvas function 实际上是在图像上绘制文本。 I'm using a package called canvasTxt which helps the text to be multiline.我正在使用名为canvasTxt的 package 来帮助文本成为多行。

  3. The createGradient function call inside updateCanvas is the image gradient for the image. updateCanvas内部的createGradient function 调用是图像的图像渐变。

I tried moving the createGradient function call below the drawTexts but then the gradient comes to the top of everything.我尝试将 createGradient function 调用移动到 drawTexts 下方,但随后渐变出现在所有内容的顶部。 The texts become darker too.文字也变暗了。

How can I make the gradient take it's value only instead of shadow color?如何使渐变仅取其值而不是阴影颜色?

Your help would be highly appreciated.您的帮助将不胜感激。

Thanks in advance提前致谢

This is because since you didn't reset the shadow options, the gradient itself is affected by the shadowing, just like it would be affected by a filter if it makes things clearer to you:这是因为由于您没有重置阴影选项,渐变本身会受到阴影的影响,就像它会受到过滤器的影响一样,如果它让您更清楚的话:

 const ctx = canvas.getContext( "2d" ); // a vertical green to transparent gradient const grad = ctx.fillStyle = ctx.createLinearGradient( 0, 0, 0, 150 ); grad.addColorStop( 0, "rgba(0,255,0)" ); grad.addColorStop( 1, "rgba(0,255,0,0.01)" ); ctx.textAlign = "center"; ctx.fillRect( 0, 0, 50, 150 ); ctx.filter = "sepia(1)"; ctx.fillRect( 75, 0, 50, 150 ); ctx.filter = "invert(1)"; ctx.fillRect( 150, 0, 50, 150 ); ctx.filter = "none"; // disable filtering ctx.shadowColor = "red"; ctx.shadowOffsetX = 15; ctx.shadowOffsetY = 25; ctx.fillRect( 225, 0, 50, 150 ); // disable shadows ctx.shadowColor = "transparent"; ctx.shadowOffsetX = 0; ctx.shadowOffsetY = 0; ctx.fillStyle = "black"; ctx.fillText( "sepia(1)", 100, 20 ); ctx.fillText( "none", 25, 20 ); ctx.fillText( "invert(1)", 175, 20 ); ctx.fillText( "shadow", 250, 20 );
 <canvas id="canvas" width="500"></canvas>

As you can see, because your gradient is not fully opaque, the shadow is visible behind it, and the rendered color is altered.正如你所看到的,因为你的渐变不是完全不透明的,阴影在它后面是可见的,并且渲染的颜色被改变了。

To workaround that, you can simply do as I did in my example:要解决此问题,您可以像我在示例中所做的那样简单地做:

// disable shadows
ctx.shadowColor = "transparent";
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;

 const canvasTxt = window.canvasTxt.default; const canvas = document.getElementById('canvas'); const ctx = canvas?.getContext('2d'); const btnDownload = document.querySelector('.btnDownload'); const fileUpload = document.querySelector('.file-upload'); const text1 = document.getElementById('text1'); const textForm1 = document.getElementById('text1-form'); const text2 = document.getElementById('text2'); const textForm2 = document.getElementById('text2-form'); const text2ShadowColor = document.getElementById('text2shadowcolor'); const text2ShadowOffsetY = document.getElementById('text2shadowoffy'); const imageForm = document.getElementById('image-form'); const imageGrad = document.getElementById('gradientcolor'); const imageGradOpacity = document.getElementById('gradientopacity'); $(fileUpload).on('change', function(e) { let imgObj = new Image(); imgObj.onload = draw; imgObj.onerror = failed; imgObj.src = URL.createObjectURL(this.files[0]); imgManipulation( e, imgObj ); }); const imgManipulation = ( e, imgObj ) => { $(textForm1).on('change keyup input', updateCanvas); $(textForm2).on('change keyup input', updateCanvas); $(imageForm).on('change keyup input', updateCanvas); function updateCanvas() { e.preventDefault(); ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.drawImage(imgObj, 0, 0); createGradient($(imageGrad).val(), $(imageGradOpacity).val()); // TEXT1 STYLES based on user input canvasTxt.fontSize = 30; canvasTxt.drawText( ctx, $(text1).val(), 0, 0, 0, 0 ); // TEXT2 STYLES ctx.shadowColor = $(text2ShadowColor).val(); ctx.shadowOffsetY = $(text2ShadowOffsetY).val(); canvasTxt.font = 20; canvasTxt.drawText( ctx, $(text2).val(), 20, 20, 0, 0 ); // clean behind ctx.shadowColor = "transparent"; ctx.shadowOffsetY = 0; } }; function hexToRgb(hex) { var result = /^#?([af\d]{2})([af\d]{2})([af\d]{2})$/i.exec(hex); return result? { r: parseInt(result[1], 16), g: parseInt(result[2], 16), b: parseInt(result[3], 16) }: null; }; function createGradient(hex, alpha) { const r = hexToRgb(hex).r.toString(); const g = hexToRgb(hex).g.toString(); const b = hexToRgb(hex).b.toString(); var gradient = ctx.createLinearGradient(800, 0, 0, 0); gradient.addColorStop(0, `rgba(${r}, ${g}, ${b}, ${alpha})`); const current_fill_style = ctx.fillStyle; ctx.fillStyle = gradient; ctx.fillRect(0, 0, canvas.width, canvas.height); // clean behind ctx.fillStyle = current_fill_style; }; function draw() { canvas.width = this.naturalWidth; canvas.height = this.naturalHeight; const nw = this.naturalWidth; const nh = this.naturalHeight; ctx.drawImage(this, 0, 0, nw, nh); }; function failed() { console.error("The provided file couldn't be loaded as an Image media"); }; $(btnDownload).on('click', function(e) { const a = document.createElement('a'); document.body.appendChild(a); a.href = canvas.toDataURL(); a.download = "canvas-image.png"; a.click(); document.body.removeChild(a); });
 #canvas{ background-color: transparent; width: 30%; height: auto; border: 1px solid #777; }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script> <script src="https://unpkg.com/canvas-txt@3.0.0/build/index.js"></script> <canvas id="canvas" width="800" height="500"></canvas> <div> <input type="file" class="file-upload" /> <button class="btnDownload">Download</button> </div> <div> <form id="text1-form"> <input type="text" id="text1" placeholder="text 1"/> </form> </div> <div> <form id="text2-form"> <input type="text" id="text2" placeholder="text 2"/> </form> </div> <div> <h2>Image Gradient and Opacity</h2> <form id="image-form"> <input type="color" id="gradientcolor" value="#000000" /> <input type="range" id="gradientopacity" min="0" max="1" value="0" step="0.05" /> </form> </div> <div> <h2>Text2 Shadow Offset X</h2> <input type="color" id="text2shadowcolor" value="#000000" /> <input type="range" id="text2shadowoffy" min="0" max="40" value="0" /> </div>

The shadowColor still work when drawing 'Gradient' next time.下次绘制“渐变”时, shadowColor仍然有效。 Add ctx.save() before, and ctx.restore() after.在之前添加ctx.save() ,在之后添加 ctx.restore( ctx.restore()

 const canvasTxt = window.canvasTxt.default; const canvas = document.getElementById('canvas'); const ctx = canvas?.getContext('2d'); const btnDownload = document.querySelector('.btnDownload'); const fileUpload = document.querySelector('.file-upload'); const text1 = document.getElementById('text1'); const textForm1 = document.getElementById('text1-form'); const text2 = document.getElementById('text2'); const textForm2 = document.getElementById('text2-form'); const text2ShadowColor = document.getElementById('text2shadowcolor'); const text2ShadowOffsetY = document.getElementById('text2shadowoffy'); const imageForm = document.getElementById('image-form'); const imageGrad = document.getElementById('gradientcolor'); const imageGradOpacity = document.getElementById('gradientopacity'); $(fileUpload).on('change', function(e) { let imgObj = new Image(); imgObj.onload = draw; imgObj.onerror = failed; imgObj.src = URL.createObjectURL(this.files[0]); imgManipulation( e, imgObj ); }); const imgManipulation = ( e, imgObj ) => { $(textForm1).on('change keyup input', updateCanvas); $(textForm2).on('change keyup input', updateCanvas); $(imageForm).on('change keyup input', updateCanvas); function updateCanvas() { e.preventDefault(); ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.drawImage(imgObj, 0, 0); createGradient($(imageGrad).val(), $(imageGradOpacity).val()); // TEXT1 STYLES based on user input canvasTxt.fontSize = 30; canvasTxt.drawText( ctx, $(text1).val(), 0, 0, 0, 0 ); // TEXT2 STYLES ctx.save() // <----------- ADD ctx.shadowColor = $(text2ShadowColor).val(); ctx.shadowOffsetY = $(text2ShadowOffsetY).val(); canvasTxt.font = 20; canvasTxt.drawText( ctx, $(text2).val(), 20, 20, 0, 0 ); ctx.restore() // <----------- ADD } }; function hexToRgb(hex) { var result = /^#?([af\d]{2})([af\d]{2})([af\d]{2})$/i.exec(hex); return result? { r: parseInt(result[1], 16), g: parseInt(result[2], 16), b: parseInt(result[3], 16) }: null; }; function createGradient(hex, alpha) { const r = hexToRgb(hex).r.toString(); const g = hexToRgb(hex).g.toString(); const b = hexToRgb(hex).b.toString(); var gradient = ctx.createLinearGradient(800, 0, 0, 0); gradient.addColorStop(0, `rgba(${r}, ${g}, ${b}, ${alpha})`); ctx.save() // <----------- ADD ctx.fillStyle = gradient; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.restore() // <----------- ADD }; function draw() { canvas.width = this.naturalWidth; canvas.height = this.naturalHeight; const nw = this.naturalWidth; const nh = this.naturalHeight; ctx.drawImage(this, 0, 0, nw, nh); }; function failed() { console.error("The provided file couldn't be loaded as an Image media"); }; $(btnDownload).on('click', function(e) { const a = document.createElement('a'); document.body.appendChild(a); a.href = canvas.toDataURL(); a.download = "canvas-image.png"; a.click(); document.body.removeChild(a); });
 #canvas{ background-color: transparent; width: 30%; height: auto; border: 1px solid #777; }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script> <script src="https://unpkg.com/canvas-txt@3.0.0/build/index.js"></script> <canvas id="canvas" width="800" height="500"></canvas> <div> <input type="file" class="file-upload" /> <button class="btnDownload">Download</button> </div> <div> <form id="text1-form"> <input type="text" id="text1" placeholder="text 1"/> </form> </div> <div> <form id="text2-form"> <input type="text" id="text2" placeholder="text 2"/> </form> </div> <div> <h2>Image Gradient and Opacity</h2> <form id="image-form"> <input type="color" id="gradientcolor" value="#000000" /> <input type="range" id="gradientopacity" min="0" max="1" value="0" step="0.05" /> </form> </div> <div> <h2>Text2 Shadow Offset X</h2> <input type="color" id="text2shadowcolor" value="#000000" /> <input type="range" id="text2shadowoffy" min="0" max="40" value="0" /> </div>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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