SVG và phần tử foreignObject

Giới thiệu về SVG

SVG (Scalable Vector Graphics) là một chuẩn mở dựa trên XML dùng để mô tả đồ họa 2D. Khác với định dạng ảnh raster như JPEG hay PNG, SVG sử dụng phương trình toán học và mô tả hình học để tạo hình ảnh, cho phép thu nhỏ hoặc phóng to mà không bị méo hay mờ. SVG hỗ trợ các đối tượng như đường thẳng, đường cong, hình chữ nhật, hình tròn, cùng với các hiệu ứng như gradient, pattern và cắt hình ảnh.

Hạn chế của phần tử text trong SVG

Phần tử text trong SVG cung cấp khả năng hiển thị văn bản cơ bản nhưng thiếu các tính năng bố cục mạnh như tự động xuống dòng, căn chỉnh. Ví dụ sau minh họa vấn đề này:

<svg xmlns="http://www.w3.org/2000/svg" width="300" height="200">
  <g>
    <rect width="200" height="100" fill="lightgray" />
    <text x="10" y="20" font-size="12" fill="black">
      This is a long text that cannot automatically wrap within the rectangle.
    </text>
  </g>
</svg>

Sử dụng foreignObject để cải thiện khả năng hiển thị văn bản

Phần tử foreignObject cho phép nhúng nội dung HTML/XML vào SVG. Ví dụ sau sử dụng foreignObject để hiển thị văn bản tự động xuống dòng:

<svg xmlns="http://www.w3.org/2000/svg" width="300" height="200">
  <g>
    <rect width="200" height="100" fill="lightgray" />
    <foreignObject x="10" width="180" height="80">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p>This is a long text that will automatically wrap within the rectangle.</p>
      </div>
    </foreignObject>
  </g>
</svg>

Xử lý SVG có text trên server

Khi cần chuyển đổi SVG chứa text sang PNG trên server, có thể sử dụng Headless Chromium qua Puppeteer:

const puppeteer = require('puppeteer');
const browser = await puppeteer.launch({ headless: true });
const page = await browser.newPage();
await page.setViewport({ width: 1000, height: 1000 });
await page.setContent(svgContent);
const buffer = await page.screenshot({ type: 'png' });
await browser.close();

Chuyển DOM thành hình ảnh

Ví dụ minh họa cách chuyển DOM thành hình ảnh bằng SVG và canvas:

<html>
<body>
  <div id="root">
    <h1>Tiêu đề</h1>
    <div class="list">
      <div class="list-item">Nhãn - Giá trị</div>
    </div>
  </div>
  <button onclick="exportImage()">Tải về</button>
  <script>
    function exportImage() {
      const node = document.getElementById('root');
      const svg = createSVGFromDOM(node);
      const img = new Image();
      img.onload = () => {
        const canvas = document.createElement('canvas');
        const ctx = canvas.getContext('2d');
        ctx.drawImage(img, 0, 0);
        const link = document.createElement('a');
        link.href = canvas.toDataURL();
        link.download = 'image.png';
        link.click();
      };
      img.src = 'data:image/svg+xml,' + encodeURIComponent(svg);
    }
  </script>
</body>
</html>

Thẻ: SVG foreignObject text rendering Puppeteer DOM to image

Đăng vào ngày 28 tháng 8 lúc 05:57