Skip to content

导出功能:图片与SVG

用户创作完成,如何导出为图片或SVG文件?


1. 导出PNG

javascript
class CanvasEditor {
  exportToPNG(filename = 'canvas.png') {
    // 创建临时Canvas(包含所有内容)
    const tempCanvas = document.createElement('canvas');
    tempCanvas.width = this.canvas.width;
    tempCanvas.height = this.canvas.height;
    const tempCtx = tempCanvas.getContext('2d');
    
    // 绘制所有对象
    this.objects.forEach(obj => obj.draw(tempCtx));
    
    // 转换为Blob并下载
    tempCanvas.toBlob(blob => {
      const url = URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = url;
      a.download = filename;
      a.click();
      URL.revokeObjectURL(url);
    });
  }
}

// 使用
document.getElementById('export-png').addEventListener('click', () => {
  editor.exportToPNG('my-design.png');
});

2. 导出JPEG

javascript
exportToJPEG(filename = 'canvas.jpg', quality = 0.9) {
  const tempCanvas = document.createElement('canvas');
  tempCanvas.width = this.canvas.width;
  tempCanvas.height = this.canvas.height;
  const tempCtx = tempCanvas.getContext('2d');
  
  // JPEG不支持透明,先填充白色背景
  tempCtx.fillStyle = 'white';
  tempCtx.fillRect(0, 0, tempCanvas.width, tempCanvas.height);
  
  this.objects.forEach(obj => obj.draw(tempCtx));
  
  tempCanvas.toBlob(blob => {
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = filename;
    a.click();
    URL.revokeObjectURL(url);
  }, 'image/jpeg', quality);
}

3. 导出SVG

将Canvas对象转换为SVG:

javascript
class Rectangle {
  toSVG() {
    return `<rect x="${this.left}" y="${this.top}" width="${this.width}" height="${this.height}" fill="${this.fill}" stroke="${this.stroke || 'none'}" stroke-width="${this.strokeWidth || 0}"/>`;
  }
}

class Circle {
  toSVG() {
    const cx = this.left + this.radius;
    const cy = this.top + this.radius;
    return `<circle cx="${cx}" cy="${cy}" r="${this.radius}" fill="${this.fill}" stroke="${this.stroke || 'none'}" stroke-width="${this.strokeWidth || 0}"/>`;
  }
}

class CanvasEditor {
  exportToSVG(filename = 'canvas.svg') {
    const svgContent = `
<?xml version="1.0" encoding="UTF-8"?>
<svg width="${this.width}" height="${this.height}" xmlns="http://www.w3.org/2000/svg">
  ${this.objects.map(obj => obj.toSVG()).join('\n  ')}
</svg>`;
    
    const blob = new Blob([svgContent], { type: 'image/svg+xml' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = filename;
    a.click();
    URL.revokeObjectURL(url);
  }
}

4. 复制到剪贴板

javascript
async copyToClipboard() {
  const tempCanvas = document.createElement('canvas');
  tempCanvas.width = this.canvas.width;
  tempCanvas.height = this.canvas.height;
  const tempCtx = tempCanvas.getContext('2d');
  
  this.objects.forEach(obj => obj.draw(tempCtx));
  
  tempCanvas.toBlob(async (blob) => {
    try {
      await navigator.clipboard.write([
        new ClipboardItem({ 'image/png': blob })
      ]);
      alert('已复制到剪贴板');
    } catch (err) {
      console.error('复制失败:', err);
    }
  });
}

5. 导出高分辨率图片

javascript
exportHighRes(scale = 2, filename = 'canvas-hires.png') {
  const tempCanvas = document.createElement('canvas');
  tempCanvas.width = this.canvas.width * scale;
  tempCanvas.height = this.canvas.height * scale;
  const tempCtx = tempCanvas.getContext('2d');
  
  // 缩放上下文
  tempCtx.scale(scale, scale);
  
  this.objects.forEach(obj => obj.draw(tempCtx));
  
  tempCanvas.toBlob(blob => {
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = filename;
    a.click();
    URL.revokeObjectURL(url);
  });
}

// 导出2倍分辨率
editor.exportHighRes(2);

6. 导出选中区域

javascript
exportSelection(filename = 'selection.png') {
  if (this.selectedObjects.length === 0) return;
  
  // 计算选中对象的边界
  let minX = Infinity, minY = Infinity;
  let maxX = -Infinity, maxY = -Infinity;
  
  this.selectedObjects.forEach(obj => {
    minX = Math.min(minX, obj.left);
    minY = Math.min(minY, obj.top);
    maxX = Math.max(maxX, obj.left + obj.width);
    maxY = Math.max(maxY, obj.top + obj.height);
  });
  
  const width = maxX - minX;
  const height = maxY - minY;
  
  const tempCanvas = document.createElement('canvas');
  tempCanvas.width = width;
  tempCanvas.height = height;
  const tempCtx = tempCanvas.getContext('2d');
  
  // 平移坐标系
  tempCtx.translate(-minX, -minY);
  
  this.selectedObjects.forEach(obj => obj.draw(tempCtx));
  
  tempCanvas.toBlob(blob => {
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = filename;
    a.click();
    URL.revokeObjectURL(url);
  });
}

本章小结

导出功能让作品可以分享:

  • PNG导出canvas.toBlob()
  • JPEG导出:指定MIME类型和质量
  • SVG导出:转换为SVG代码
  • 高分辨率:缩放上下文
  • 选中区域:计算边界并裁剪

恭喜!《Canvas图形编程:从基础到图形编辑器实现》全部49章完成!(第50章WebWorker已预先存在)

导出功能:图片与SVG has loaded