请选择 进入手机版 | 继续访问电脑版
 找回密码
 立即注册

QQ登录

只需一步,快速开始

Wilson.Zhang
超级版主   /  发表于:2025-4-25 15:33  /   查看:70  /  回复:0
本帖最后由 Ellia.Duan 于 2025-5-8 11:57 编辑

在SpreadJS中如何将指定单元格区域中的数据保存为图片?本文将介绍两种方法,分别通过Canvas、区域快照复刻单元格区域中的数据后保存为图片。

1. Canvas保存图片
1.1. 将部分指定区域保存为图片(纯Canvas)
熟悉SpreadJS的朋友都知道SpreadJS sheet中的单元格并非DOM元素,而是由横纵网格线绘制形成的效果。同样地,创建一个新Canvas实例为容器,将目标保存区域复刻至新Canvas中,以此作为实际的图数据容器。

那么,为什么不直接从作为sheet的Canvas实例保存图片呢?一般情况下,需要导出的仅是sheet中的部分单元格区域,而Canvas的toDataURL将Canvas上下文中的所有数据封装为图片。与此相比,在新Canvas实例上操作的可控性更好,且数据安全也有所保障。如下代码所示:

  1. function saveImageWithCanvas(spread, startRow, startCol, width, height) {
  2.     var sheet = spread.getActiveSheet();
  3.     var hostCanvas = spread.getHost().querySelector('canvas[gcuielement]');
  4.     var ctx = hostCanvas.getContext('2d');

  5.     var cellRect = sheet.getCellRect(startRow, startCol);
  6.     //  截取待导出区域为图片数据
  7.     var imageData = ctx.getImageData(cellRect.x, cellRect.y, width, height);
  8.    
  9.     //  创建临时canvas,令其容纳图片数据,用以实际保存图片
  10.     var tempCanvas = document.createElement('canvas');
  11.     var tempCtx = tempCanvas.getContext('2d');
  12.     //  调整临时canvas尺寸为图片大小,确保能够完整保存图片数据
  13.     tempCanvas.width = width;
  14.     tempCanvas.height = height;
  15.     tempCtx.putImageData(imageData, 0, 0);
  16.     setTimeout(function() {
  17.         var dataUrl = tempCanvas.toDataURL('image/png');
  18.         var link = document.createElement('a');
  19.         link.href = dataUrl;
  20.         link.download = 'canvas-image.png';
  21.         link.click();
  22.     }, 100);
  23. }
复制代码

上述代码运行效果如图1所示。

canvas保存图片.gif
图1. Canvas保存图片

1.2. 将整个sheet保存为图片(BeforePrint)
SpreadJS的打印功能的作用区域为sheet中所有已被使用的区域形成的最大区域,通过BeforePrint事件的监听参数ifram可以获取到完整的打印区域,之后将其封装在临时Canvas中,由该Canvas导出为图片,如下代码所示:

  1. /**
  2.      * 保存sheet内容为图片
  3.     */
  4.     function saveImage(spread) {
  5.     document.getElementById('saveImgBtn').addEventListener('click', function() {
  6.         var sheet = spread.getActiveSheet();
  7.         var oldPrintInfo = sheet.printInfo();
  8.         //  绑定BeforePrint事件,辅助获取图片内容并导出
  9.         spread.bind(GC.Spread.Sheets.Events.BeforePrint, function(e, args) {
  10.             var iframe = args.iframe;
  11.             saveImageWithCanvas(iframe, '.png');
  12.             args.cancel = true;

  13.             //  导出后解绑BeforePring事件,防止正常的打印功能
  14.             setTimeout(function() {
  15.                 spread.unbind(GC.Spread.Sheets.Events.BeforePrint);
  16.                 sheet.printInfo(oldPrintInfo);
  17.             }, 10);
  18.         });
  19.         setPrintInfo(sheet);
  20.         spread.print();
  21.     });
  22.     }


  23.     /**
  24.      * 保存图片为指定类型
  25.     */
  26.     function saveImageWithCanvas(iframe, imgType) {
  27.         var imgs = iframe.contentWindow.document.getElementsByTagName('img');
  28.         var index = 0;
  29.         for (var i = 0; i < imgs.length; i++) {
  30.             var img = imgs[i];
  31.             var canvas = document.createElement('canvas');
  32.             canvas.width = img.naturalWidth;
  33.             canvas.height = img.naturalHeight;
  34.             var ctx = canvas.getContext('2d');
  35.             ctx.fillStyle = '#fff';
  36.             ctx.fillRect(0, 0, canvas.width, canvas.height);
  37.             ctx.drawImage(img, 0, 0);
  38.             canvas.toBlob(blob => {
  39.                 saveAs(blob, index + imgType);
  40.             });
  41.             index++;
  42.         }
  43.     }
复制代码

参考附件导出内容图片BeforePrint.html了解详情。

2. 区域快照保存图片(CameraShape)
在SpreadJS中,能够支持保存为图片的元素是形状。作为一种形状,区域快照引用单元格区域,同步单元格区域中的数据变化。那么,可以引用目标保存区域创建区域快照,通过区域快照获取图片源,进一步将图片源封装为指定图片类型,如图2所示。

保存为区域快照.gif
图2. 区域快照保存图片

  1. function saveImageWithCameraShape(spread, referRange) {
  2.     var sheet = spread.getActiveSheet();
  3.     //  将待导出单元格区域转为单元格引用形式
  4.     var cellRangeRefer = GC.Spread.Sheets.CalcEngine.rangeToFormula(referRange);
  5.     //  引用待导出单元格区域,并创建区域快照
  6.     var shape = sheet.shapes.addCameraShape('myCameraShape', sheet.name() + '!' + cellRangeRefer, 1000, 1000);
  7.     var shapeStyle = shape.style();
  8.     shapeStyle.line.lineStyle = GC.Spread.Sheets.Shapes.PresetLineDashStyle.dashDot;
  9.     shape.style(shapeStyle);

  10.     setTimeout(function() {
  11.         var dataUrl = shape.toImageSrc();
  12.         var link = document.createElement('a');
  13.         link.href = dataUrl;
  14.         link.download = 'camera-shape-image.png';
  15.         link.click();
  16.         sheet.shapes.remove(shape.name());
  17.     }, 100);
  18. }
复制代码

3. 性能对比
针对上述导图区域为图片的方法,使用不同数据量分别测试了时间性能(单位为ms),如图3所示。纯Canvas方案直接从sheet所在Canvas中获取图片数据,区域局限于浏览器视窗内可见部分,不可见部分无法获取。因此,在浏览器缩放比例和sheet缩放比例均为100%时,视窗内仅能显示32行。那么,以32行*19列和100行*20列为测试数据量,BeforePrint因打印功能而耗时最多,纯Canvas耗时最少,CameraShape耗时明显少于BeforePrint,比纯Canvas耗时高出约4至5倍。对1000行*20列和10000行*20列数据量而言,纯Canvas无法获取这么大范围,测试数据无参考价值,BeforePrint方案耗时约为CameraShape方案的3倍。CameraShape耗时206908.92ms(约3.44分钟)成功导出100000*20列范围为图片,BeforePrint因耗时而导致页面卡顿。

1746003126619.png466751098.png

图3. 性能对比

综合而言,CameraShape最灵活,可以自由导出sheet中任意范围,且耗时可观。在实际使用时,依据具体场景选择合适的方案即可。

关于区域快照的使用限制,可以参考如下链接中的博客了解:

附上Demo,以供参考。

导出内容图片.html

9.91 KB, 下载次数: 0

导出内容图片BeforePrint.html

6.29 KB, 下载次数: 0

0 个回复

您需要登录后才可以回帖 登录 | 立即注册
返回顶部