HTML5画布:更改图像后,在图像上绘制的文本停止显示 [英] HTML5 Canvas: Text drawn on image stops showing when image is changed

查看:60
本文介绍了HTML5画布:更改图像后,在图像上绘制的文本停止显示的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

因此,我有一个简单的图像编辑器,使用画布来绘制用户选择的图像和一些文本.也就是说,用户可以上传图像,然后如果需要,可以添加文本或仅更改图像的渐变.

So I have this simple image editor where I'm using a canvas to draw in a user-selected image and some texts. 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. 上传随机图片.
  2. 在输入字段中输入内容.
  3. 上传和更改图像.

您将看到文本消失.

这是代码:

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      = 70;
        ctx.fillStyle           = "white";
        canvasTxt.drawText(
            ctx, 
            $(text1).val(), 
            0, 
            0, 
            200, 
            200
        );


        // TEXT2 STYLES
        canvasTxt.font          = 50;
        ctx.fillStyle           = "white";
        canvasTxt.drawText(
            ctx, 
            $(text2).val(),
            20, 
            20, 
            200, 
            200
        );
    }
};

function hexToRgb(hex) {
    var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\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>

代码摘要:

1:首先,我有fileUpload事件侦听器.它从用户那里获取图像,并创建一个图像对象并将其绘制在画布上.然后以imgObj和event作为参数调用imgManipulation函数.

1: First I have the fileUpload event listener. It takes in an image from the user and creates an image object and draws it on the canvas. Then imgManipulation function is called with the imgObj and event as its arguments.

imgManipulation函数从文本的输入事件侦听器开始.也就是说,只要输入发生更改,即用户写了些东西,就会调用updateCanvas函数.

The imgManipulation function starts off with the input event listeners for the texts. That is whenever there is a change in the input, that is a user writes something, updateCanvas function is called.

updateCanvas函数实际上在图像上绘制文本.我正在使用一个名为canvasTxt的程序包,该程序包可以使文本变为多行.

The updateCanvas function actually draws the texts on the image. I'm using a package called canvasTxt which helps the text to be multiline.

更改图像后,如果用户在输入字段中先前输入过用户文本的位置写字母,则该文本会神奇地显示.

After changing the image, the text magically appears if the user writes a letter on the input field where there is previously typed user text.

如何在不删除用户键入的文本的情况下更改图像?

How can I change the image without removing the text typed by the user?

我们将非常感谢您的帮助.

Your help would be highly appreciated.

预先感谢

推荐答案

您可以看到有两种绘制图像的方法: imgObj.onload = draw; updateCanvas

U can see there are two ways to draw image: imgObj.onload = draw; and updateCanvas.

因此,当更改图像时,调用 draw 函数而不填充文本.

So when change the image, draw function called without filling text.

最好将画布的绘图功能放在相同的功能中.

It's better to put the drawing things of the canvas in the same function.

喜欢这个.

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 );
});  

// -----AND `reDraw` function
function reDraw (imgObj) {
        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      = 70;
        ctx.fillStyle           = "white";
        canvasTxt.drawText(
            ctx, 
            $(text1).val(), 
            0, 
            0, 
            200, 
            200
        );


        // TEXT2 STYLES 
        canvasTxt.fontSize      = 50; // canvasTxt.font = 50;
        ctx.fillStyle           = "white";
        canvasTxt.drawText(
            ctx, 
            $(text2).val(),
            20, 
            20, 
            200, 
            200
        );
}

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();
        reDraw(imgObj) // <-------- CALL `reDraw`
    }
};

function hexToRgb(hex) {
    var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\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()
    ctx.fillStyle = gradient;
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    ctx.restore()
};


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);
    reDraw(this) // <-------- CALL `reDraw`
};

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>

这篇关于HTML5画布:更改图像后,在图像上绘制的文本停止显示的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆