chrome扩展画布不在循环内绘制图像

时间:2013-07-08 04:46:53

标签: canvas google-chrome-extension html5-canvas

我正在尝试制作屏幕截图,通过使用scrollTo移动窗口并在弹出窗口中将图像拼接在一起来获取整个页面的屏幕截图。但是,我的问题是,我回来的所有图像都没有被绘制/没有出现在画布上。

popup.js

function draw(ctx, image, x ,y) {
  console.log(image);
  var img = new Image();
  img.src = image;
  img.onload = function() {
    ctx.drawImage(img, x, y);
    console.log('x',x);
    console.log('y',y);
  };
}

function screenshot(response) {
  console.log('screenshot');
  var canvas = document.getElementById('imagecanvas'),
    fullHeight = response.height,
    fullWidth = response.width,
    visibleHeight = response.visibleHeight,
    visibleWidth = response.visibleWidth,
    x = 0,
    y = 0;

  canvas.height = fullHeight;
  canvas.width = fullWidth;

  var ctx = canvas.getContext('2d');
  // console.log('canvas', canvas);
  // console.log('context', ctx);
  //start at the top
  window.scrollTo(0, 0);

  while (y <= fullHeight) {
    chrome.tabs.captureVisibleTab(null, {
      format: 'png'
    }, function (image) {
      draw(ctx, image, x, y);
    });

    // console.log('x',x);
    // console.log('y',y);

    y += visibleHeight;
    window.scrollTo(x, y);
  }
}

chrome.tabs.query({
  'active': true,
  'currentWindow':true
}, function(tab){
  console.log('sending message');
  chrome.tabs.sendMessage(tab[0].id, {
    message: 'dom'
  }, function(response){
    console.log('response', response);
    screenshot(response);
  });
});

popup.html

<!doctype html>
<html>
  <head>
    <title>Chrome Snapshot</title>
    <style>
    #imagecanvas {
      z-index: 100;
    }
    </style>
    <script src="jquery-2.0.2.min.js"></script>
    <script src="popup.js"></script>
  </head>
  <body>
    <canvas id="imagecanvas"> </canvas>
  </body>
</html>

content.js

chrome.runtime.onMessage.addListener(
  function(request, sender, sendResponse) {
    if (request.message === 'dom') {
      sendResponse({
        height:         document.height,
        width:          document.width,
        visibleHeight:  window.innerHeight,
        visibleWidth:   window.innerWidth
      });
    }
  });

的manifest.json

{
  "manifest_version": 2,
  "name": "test",
  "description": "Save images and screenshots of sites to Dropbox.",
  "version": "1.0",
  "permissions": [
    "<all_urls>",
    "tabs"
  ],
  "browser_action": {
    "default_icon": "icon.png",
    "default_popup": "popup.html"
  },
  "background": {
    "scripts": [
      "jquery-2.0.2.min.js"
    ],
    "persistent": false
  },
  "content_scripts" : [{
    "all_frames": true,
    "matches" : ["*://*/*"],
    "js" : ["content.js"],
    "run_at": "document_end"
  }]
}

编辑以回应Rob的评论

到目前为止我所拥有的内容:我可以看到页面正在滚动,但现在,来自captureVisibleTab的图像将返回为undefined。

popup.js

var ctx,
    fullHeight,
    fullWidth,
    x,
    y,
    visibleHeight,
    visibleWidth;

function draw(ctx, image, x ,y) {
  console.log(image);
  var img = new Image();
  img.src = image;

  img.onload = function() {
    ctx.drawImage(img, x, y);
    // console.log('x',x);
    // console.log('y',y);
  };
}

function next(tabID) {
  chrome.tabs.captureVisibleTab(null, {
    format: 'png'
  }, function(image) {
    console.log(image);
    draw(ctx, image, x, y);
    y += visibleHeight;

    if (y < fullHeight) {
      chrome.tabs.sendMessage(tabID, {
          message: 'scroll',
          x: x,
          y: y
      }, function() {
        next(tabID);
      });
    }
  });
}

function screenshot(response, tabID) {
  console.log('screenshot');
  var canvas = document.getElementById('imagecanvas');

  fullHeight = response.height;
  fullWidth = response.width;

  visibleHeight = response.visibleHeight,
  visibleWidth = response.visibleWidth;

  x = 0,
  y = 0;

  canvas.height = fullHeight;
  canvas.width = fullWidth;

  ctx = canvas.getContext('2d');

  chrome.tabs.sendMessage(tabID, {
        message: 'scroll',
        x: x,
        y: y
    }, function() {
      next(tabID);
    });
}

chrome.tabs.query({
  active:true,
  lastFocusedWindow:true
}, function(tab){
  var tabID = tab[0].id;
  console.log('sending message', tabID);
  chrome.tabs.sendMessage(tabID, {
    message: 'dom'
  }, function(response){
    console.log('dom info', response);
    screenshot(response, tabID);
  });
});

content.js

chrome.runtime.onMessage.addListener(
  function(request, sender, sendResponse) {
    if (request.message === 'dom') {
      sendResponse({
        height:         document.height,
        width:          document.width,
        visibleHeight:  window.innerHeight,
        visibleWidth:   window.innerWidth
      });
    } else if (request.message == 'scroll') {
      window.scrollTo(request.x, request.y);
        sendResponse();
    }
  });

1 个答案:

答案 0 :(得分:3)

您的代码有两个重要问题。

第一个问题是你假设window.scrollTo(0, 0);滚动标签的内容。这不是真的,它会滚动弹出窗口的文档。

第二个问题是你在一个循环中调用一个异步方法,它在每次迭代时改变y变量。在此captureVisibleTab的回调中,您再次读取y变量,但由于在循环结束时调用了所有回调,因此它始终是相同的值。

顺便说一下,这个值也是错误的。你循环到y <= fullHeight。这应该是y < fullHeight,因为一旦你到达页面底部,就不需要再拍一张截图了。

至少,您需要将循环更改为(递归)回调集。

// popup.js
  function next() {
    chrome.tabs.captureVisibleTab(null, {
      format: 'png'
    }, function (image) {
      draw(ctx, image, x, y);
      y += visibleHeight;

      window.scrollTo(x, y); // TODO
      next();
    });
  }
  // Initialize recursion
  next();

这种方法略胜一筹,至少你看到画布上画了一些东西。但它仍然不正确,因为你仍然在弹出脚本中调用window.scrollTo。解决此问题的正确方法是将scrollTo方法委托给内容脚本,并使用message passing来调用滚动。例如:

// popup.js
      //window.scrollTo(x, y); // TODO
      //next();
      chrome.tabs.sendMessage(null, {
          request: 'scroll',
          x: x,
          y: y
      }, next);

// contentscript.js
chrome.runtime.onMessage.addListener(function(message, sender,sendResponse) {
    if (message.request == 'scroll') {
        window.scrollTo(message.x, message.y);
        sendResponse();
    }
});

最后一个建议:我建议使用activeTab permissionchrome.tabs.executeScript在需要时插入内容脚本,而不是在所有标签中插入内容脚本。这使您的扩展程序不那么沉重,并且无需<all_urls>权限。