You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Canvas.toDataURL生成不完整图像的Chrome扩展技术问题

问题:Chrome扩展中Canvas生成的Data URL不完整

我正在开发一款ChromeOS的Chrome扩展,实现每日更换AI生成壁纸的功能,这是我的第一个纯JS项目。开发进度如下:

  • 完成从Nightcafe爬取最新AI图像的网络爬虫(后续将支持用户自定义)
  • 实现定时更换壁纸的功能

当前核心问题是AI生成图像尺寸随机,无法适配16:9屏幕。由于找不到无需密钥的公共API(代码库将托管在GitHub),我参考了纯JS通过Canvas处理图像的填充方案并整合到代码中,但遇到了异常:

调用console.log(canvas.toDataURL('image/png'))输出的Data URL仅加载图像的一部分,剩余区域为白色,但在background.html的开发者控制台中,Canvas能完整显示图像(包括黑色填充区域)。不同比例的AI图像缺失程度不同:窄图显示超过一半,宽图仅显示1/5。尝试添加各种延迟确保处理完成后生成URL,问题依旧。

操作步骤:更新扩展后,在扩展开发者控制台执行create()创建标签页,在该标签页控制台执行test(),Canvas显示正常,但生成的Data URL不完整。


相关代码

Background.js

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');

// chrome.alarms.create(
//   'test',
//   {delayInMinutes: 1, periodInMinutes: 1},
// );

function fillBlur(link) {
  var img = document.createElement('img');
  img.crossOrigin = 'Anonymous';

  img.onload = function(){
    var dx = 0;
    var dy = 0;

    var calculatedHeight = Math.round((img.width / 16) * 9);
    var calculatedWidth = Math.round((img.height / 9) * 16);

    //Need to pad above and below
    if (calculatedHeight > img.height) {
        dy = Math.round((calculatedHeight - img.height) / 2);
        canvas.width = img.width;
        canvas.height = calculatedHeight;
    } else {
        dx = Math.round((calculatedWidth - img.width) / 2);
        canvas.width = calculatedWidth;
        canvas.height = img.height;
    }

    ctx.fillStyle = 'black';
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    ctx.drawImage(img, dx, dy, img.width, img.height);
  }
  img.src = link;

  setTimeout(function() {
    console.log(canvas.toDataURL('image/png'));
  }, 5000);
  // ctx.filter = 'blur(15px)';
}

function getArtLink(link)
{
    var xmlHttp = new XMLHttpRequest();
    xmlHttp.open("GET", link, false ); // false for synchronous request
    xmlHttp.send( null );
    var r = xmlHttp.responseText;
    var pos = r.indexOf("og:image") + 19;
    var posEnd = r.indexOf('"/><meta property="og:image:alt"') -1;
    return r.substring(pos, posEnd);
}

// chrome.alarms.onAlarm.addListener(function(alarm) {
//   if (alarm.name === "test") {
//     chrome.wallpaper.setWallpaper(
//       {
//         'url': fillBlur(getArt('https://creator.nightcafe.studio/explore?q=new')),
//        'layout': 'CENTER_CROPPED',
//         'filename': 'test_wallpaper'
//       },
//       function() {}
//     );
//   }
// });

function create(){
  chrome.tabs.create({url: chrome.extension.getURL('background.html')});
}

function test(){
    var link = 'https://creator.nightcafe.studio/explore?q=new';
    fillBlur(getArtLink(link));
}

background.html

<html>
    <head>
        <canvas id="canvas" width="200" height="100" style="border:1px solid #000000;"></canvas>
        <script src="background.js"></script>
    </head>
    <body></body>
</html>

manifest.json

{
    "manifest_version": 2,
    "name": "Mason Test App",
    "description": "Mason Test App 2",
    "version": "1.1",
    "icons": {
    "128": "128.ico"
    },
    "background": {
        "page": "background.html",
        "persistent": false
      },
    "permissions": [
        "tabs",
        "alarms",
        "wallpaper",
        "*://creator.nightcafe.studio/*"
      ]
}

解决方案

问题根源

  1. 固定延迟的setTimeout无法保证图像绘制完成后再生成Data URL,存在时序问题。
  2. 修改Canvas尺寸后,绘图上下文的状态会被重置,可能导致绘制不完整。
  3. 初始Canvas的固定宽高会限制动态尺寸设置的效果。

修复步骤

  1. 将Data URL生成逻辑移到img.onload回调内部,确保绘图完成后再执行:

    img.onload = function(){
        // 原有尺寸计算、Canvas设置、绘图代码...
    
        // 绘图完成后立即生成Data URL
        console.log(canvas.toDataURL('image/png'));
    }
    
  2. 移除初始Canvas的固定宽高,让代码动态控制尺寸:
    修改background.html中的Canvas标签:

    <canvas id="canvas" style="border:1px solid #000000;"></canvas>
    
  3. 修改Canvas尺寸后重新获取绘图上下文(避免状态丢失):

    if (calculatedHeight > img.height) {
        dy = Math.round((calculatedHeight - img.height) / 2);
        canvas.width = img.width;
        canvas.height = calculatedHeight;
        ctx = canvas.getContext('2d'); // 重新获取上下文
    } else {
        dx = Math.round((calculatedWidth - img.width) / 2);
        canvas.width = calculatedWidth;
        canvas.height = img.height;
        ctx = canvas.getContext('2d'); // 重新获取上下文
    }
    
  4. 替换同步XMLHttpRequest为异步请求(避免阻塞主线程):

    function getArtLink(link, callback) {
        var xmlHttp = new XMLHttpRequest();
        xmlHttp.open("GET", link, true);
        xmlHttp.onload = function() {
            if (xmlHttp.status === 200) {
                var r = xmlHttp.responseText;
                var pos = r.indexOf("og:image") + 19;
                var posEnd = r.indexOf('"/>') - 1; // 更鲁棒的匹配逻辑
                callback(r.substring(pos, posEnd));
            }
        }
        xmlHttp.send(null);
    }
    

    调用方式修改为:

    function test(){
        var link = 'https://creator.nightcafe.studio/explore?q=new';
        getArtLink(link, function(imgUrl) {
            fillBlur(imgUrl);
        });
    }
    

额外优化:实现模糊填充效果

如果需要还原参考网站的模糊填充逻辑,可以在绘制黑色背景后添加模糊原图填充:

// 绘制模糊背景
ctx.filter = 'blur(15px)';
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
ctx.filter = 'none'; // 重置滤镜
// 绘制清晰原图
ctx.drawImage(img, dx, dy, img.width, img.height);

内容的提问来源于stack exchange,提问作者Masong19hippows

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 00:01:01