Thứ hai, 16/03/2020 | 00:00 GMT+7

Tải xuống image do Canvas API tạo bằng toBlob


Đối với Purple11, một dự án phụ của tôi được xây dựng bằng Gatsby, tôi đã tạo một trình tạo kết cấu cloud đơn giản sử dụng bộ lọc SVG và API Canvas bên dưới. Phần bộ lọc SVG cho phép tôi dễ dàng tự tạo hiệu ứng kết cấu cloud , một phần lớn là nhờ bộ lọc feTurbilities , nhưng tôi sẽ giữ chủ đề hấp dẫn về bộ lọc SVG cho một bài viết khác .

Để cho phép user tải kết cấu đã tạo xuống máy của họ dưới dạng file Jpeg, SVG nội tuyến (có áp dụng bộ lọc) trước tiên cần được vẽ trên đối tượng canvas, vì rất tiếc là không có cách nào để tạo file có thể download trực tiếp từ nội tuyến Đồ họa SVG. Rõ ràng, bạn có thể bỏ qua toàn bộ phần SVG to Canvas trực tiếp đến vấn đề nếu bạn ở đây chỉ để biết cách download một hình ảnh được vẽ trực tiếp bằng cách sử dụng Canvas API với toBlob .

Nếu bạn là người mới sử dụng Canvas API nói chung và muốn có cái nhìn tổng quan, hãy xem bài viết này .

SVG nội tuyến sang Canvas

Đầu tiên, bạn cần sử dụng phương thức DOM để chọn phần tử SVG nội tuyến của bạn . Giả sử SVG của ta có idmy-svg :

const mySVG = document.getElementById('my-svg');

Và sau đó bạn sẽ sử dụng XMLSerializer để tuần tự hóa nội dung của SVG và btoa (nhị phân thành ascii) để tạo version base64 của nó:

const xml = new XMLSerializer().serializeToString(mySVG);
const svg64 = btoa(xml);

Sau đó, bạn có thể tạo file có thể download ngay từ chuỗi được mã hóa base64, nhưng vấn đề tôi gặp phải là hầu hết các trình duyệt áp đặt giới hạn về kích thước của chuỗi được mã hóa base64 đó để được download dưới dạng file . Vì vậy, tôi đã phải tích lũy từ thời điểm đó để vượt qua hạn chế đó.

Tạo một phần tử Hình ảnh HTML mới và đặt thuộc tính src của nó thành version base64 của SVG của ta :

const image = new Image();
const b64Start = 'data:image/svg+xml;base64,';
image.src = b64Start + svg64;

Và bây giờ ta có một phần tử hình ảnh HTML thực tế trên trang với hình ảnh phản chiếu của SVG, ta có thể vẽ nó vào bối cảnh Canvas 2D.

Đầu tiên, ta cần tạo một bối cảnh Canvas 2D bằng kích thước của hình ảnh của ta . Giả sử rằng bạn đã có một phần tử canvas trên trang với idmy-canvas :

const canvas = document.getElementById('my-canvas');
const ctx = canvas.getContext('2d');
ctx.fillStyle = 'white';
ctx.fillRect(0, 0, image.naturalWidth, image.naturalHeight);

Và ta có thể lắng nghe sự kiện onload trên phần tử hình ảnh mà ta đã tạo để thực sự vẽ nó trên đối tượng ngữ cảnh canvas của ta :

image.onload = () => {
  ctx.drawImage(image, 0, 0, image.naturalWidth, image.naturalHeight);
};

Được rồi, bây giờ với tất cả những trò tai quái đó, cuối cùng ta đã có kết quả SVG nội tuyến của ta được vẽ thành một đối tượng canvas. Ta có thể chuyển sang phần thú vị và tạo ra một file có thể download , nhờ vào phương thức canvas ' toBlob .

Tạo hình ảnh JPEG hoặc PNG có thể download bằng toBlob

Như tên gọi của nó, phương thức toBlob biến một hình ảnh được vẽ bằng canvas thành một đốm màu. Một đốm màu là một đại diện binary của một chuỗi, sau đó có thể được download dưới dạng file trên máy của bạn.

toBlob đầu tiên nhận một hàm gọi lại làm đối số, hàm này nhận chính blob và trong lệnh gọi lại, bạn có thể tiếp tục làm bất cứ điều gì bạn muốn với blob. toBlob cũng có thể có 2 đối số bổ sung, kiểu mime (mặc định là image/png ) và chất lượng, mong đợi một số từ 0 (chất lượng 0%) đến 1 (chất lượng 100%) trở nên hữu ích khi sử dụng kiểu mime mất dữ liệu như image/jpeg .

Ví dụ: điều này sẽ tạo ra một Jpeg blob ở chất lượng 90%:

canvas.toBlob(
  blob => {
    // do something with the blob here...
  },
  'image/jpeg',
  0.9,
);

URL.createObjectURL

Những gì ta có thể làm là tạo một URL từ blob hiện tại trong bộ nhớ bằng URL.createObjectURL .

Ta chỉ có thể chọn một thẻ liên kết trên trang và đặt thuộc tính href của nó thành URL:

canvas.toBlob(
  blob => {
    const anchor = document.getElementById('download-link');
    anchor.href = URL.createObjectURL(blob);
  },
  'image/jpeg',
  0.9,
);

Sau đó, user sẽ chỉ cần nhấp vào neo để bắt đầu download file .


Nhưng ta có thể làm tốt hơn và bắt đầu download file tự động, vì vậy ta sẽ sử dụng một thủ thuật nhỏ trong đó ta lập trình tạo phần tử neo ( a ) và nhấp vào nó theo chương trình để tự động kích hoạt download :

canvas.toBlob(
  blob => {
    const anchor = document.createElement('a');
    anchor.download = 'my-file-name.jpg'; // optional, but you can give the file a name
    anchor.href = URL.createObjectURL(blob);

    anchor.click(); // ✨ magic!

    URL.revokeObjectURL(anchor.href); // remove it from memory and save on memory! 😎
  },
  'image/jpeg',
  0.9,
);

Bạn cũng sẽ nhận thấy rằng với hình ảnh được download tự động của ta , ta có thể giải phóng / dọn dẹp ánh xạ từ blob được tạo thành ánh xạ URL khỏi bộ nhớ vì blob hiện đã được download dưới dạng file trên máy nên ta đã thực hiện xong.

Kết thúc

Điều này có vẻ giống như rất nhiều sự cố gắng để có được những gì ta cần, nhưng đây là kiểu cài đặt bạn sẽ làm một lần và sau đó quay lại tập trung vào các tính năng thực tế của ứng dụng quần bạn muốn . Thêm vào đó, khi những gì ta muốn lưu được vẽ vào bối cảnh canvas, phương thức toBlob giúp bạn dễ dàng cho phép lưu file ở bất kỳ định dạng nào và chất lượng phù hợp nhất với nhu cầu của ứng dụng của bạn.


Tags:

Các tin liên quan