2016-01-27 14 views
9

Thiết lập nềnCó thể tạo hình ảnh (blob hoặc url dữ liệu) trong công nhân web từ getImageData của bối cảnh canvas không?

Tôi có một ứng dụng web liên quan đến việc tạo hình ảnh từ một tập hợp các hình ảnh khác. Cách tôi đã chọn để làm điều đó là bằng cách đọc trong một tập hợp các hình ảnh và đặt chúng trên một khung HTML. Sau đó, tôi xuất mỗi canvas thành jpeg thành API của bên thứ ba bằng cách sử dụng toDataURL và chuyển đổi nó thành Blob. Vấn đề tôi đang phải đối mặt là tôi có nhiều canvases tất cả xuất dữ liệu dưới dạng jpg và nó đang tiêu tốn rất nhiều tài nguyên. Ứng dụng sẽ chậm và không phản hồi khi mỗi canvas cố gắng gọi toDataURL.

Câu hỏi

Tôi đã phát hiện ra rằng gọi một canvas toDataUrl() hoặc toBlob() có thể rất chậm nhất là đối với kích thước canvas lớn. Tôi muốn sử dụng tính chất đa luồng của công nhân web.

Trước tiên, tôi đã thử chuyển trong đối tượng canvas nhưng đã xảy ra lỗi. Nó chỉ ra các đối tượng là một vấn đề và có vẻ như họ hoặc là có được chuyển đổi thành chuỗi hoặc thất bại khi họ không thể được nhân bản. Dù bằng cách nào, tôi thấy rằng việc truyền dữ liệu hình ảnh của một ngữ cảnh không hoạt động. Dữ liệu được chuyển dưới dạng giá trị RGB thô dưới dạng Uint8ClampedArray từ phương thức ngữ cảnh của canvas getImageData().

Main.js

var canvas = document.createElement('canvas'); 
var context = canvas.getContext('2d'); 
var worker = new Worker('myWorker.js'); 
worker.postMessage({ 
    image: context.getImageData(0, 0, canvas.width, canvas.height) 
}); 

myWorker.js

this.onmessage = function(e) { 
    // GOAL: turn e.data.image into an image blob or dataUrl and return it. 
    // e.g. this.postMessage(new Blob([e.data.image.data], {type: 'image/jpg'}); 
} 

Tôi nghĩ rằng nó đi xuống đến biết làm thế nào để chuyển đổi một Uint8ClampedArray nắm giữ các thông tin RGB vào jpg/png dữ liệu.

Lý do tại sao tôi nghĩ điều này có thể hữu ích là tôi tin rằng getImageData chỉ sao chép cấu trúc dữ liệu hiện có từ ngữ cảnh canvas và do đó không tốn kém như toDataUrl. Tôi bắt hồ sơ cá nhân CPU trong khi gọi một cái gì đó tương tự như các khối mã bên dưới:

var image = context.getImageData(0, 0, canvas.width, canvas.height) 
var dataUrl = canvas.toDataURL('image/jpeg'); 

và nhận được:

Performance results from getImageData and toDataURL

Vì vậy, do đó, tôi muốn giảm tải gánh nặng của quá trình vào một nhân viên web. Tôi thậm chí không bận tâm nếu phải mất nhiều thời gian hơn trong công nhân web miễn là nó xảy ra trong một quá trình khác.

Vài suy nghĩ thêm về nó:

  • Thêm một thư viện thêm để làm việc chuyển đổi là không sao, nhưng điểm thưởng cho cung cấp như thế nào để thêm một thư viện bên ngoài như một sự phụ thuộc vào các file lao động web. Ngay bây giờ tôi đang sử dụng trình duyệt cho ứng dụng. Có lẽ tạo một gói trình duyệt khác cho nhân viên web?
  • Tôi cần một jpeg cuối cùng (đối với API của bên thứ ba) để chuyển đổi thành png chỉ tốt như là một bước chuyển đổi thành jpeg.
  • tôi đã cố gắng hạ thấp encoderOptions, tùy chọn thứ hai trong toDataURL, như là một cách để tăng tốc độ quá trình này, nhưng tôi đã không nhìn thấy nhiều sự thay đổi
+2

Điều đó có thể thực hiện được, nhưng thực sự khó khăn và tôi không chắc bạn sẽ có những lợi ích gì: Bạn có thể tạo Blob và gửi nó trở lại trang chính từ một Web Worker. Bạn có thể thực hiện việc mã hóa thành jpeg hoặc png (ngay cả khi tôi khuyên bạn nên tìm kiếm một số thư viện). Bắt đầu với png, [thông số kỹ thuật] (https://www.w3.org/TR/PNG-Introduction.html) rõ ràng hơn jpeg. lưu ý: bạn cũng sẽ cần phải gửi siêu dữ liệu của hình ảnh. Nhưng hoạt động nặng nhất là 'ctx.getImageData()'. Tôi không chắc chắn bạn sẽ giành chiến thắng bất cứ điều gì bằng cách đi qua phần nén cho một Web Worker. – Kaiido

+0

Có thể bạn sẽ cho chúng tôi thấy mã của bạn để chúng tôi có thể biết liệu có thể cải thiện điều gì đó từ đó không. (ví dụ: bạn có sử dụng một số phương pháp không đồng bộ để GUI không chặn không?) – Kaiido

+0

@Kaiido - Tôi đã cập nhật câu hỏi để phản ánh thêm hiểu biết của mình về vấn đề này. Có vẻ như getImageData không quá nguy hiểm như mong đợi. Và đối với mã của tôi, tôi đang sử dụng phương thức trì hoãn của underscore để bọc canvas.toDataURL để không khóa giao diện người dùng nhưng ngay khi phương thức bắt đầu (cuối cùng) nó sẽ chặn các js khác thực thi. Ngoài ra, nó đáng chú ý là tôi đang làm điều này nhiều lần cho nhiều hình ảnh trên trang, vì vậy chi phí cao hơn 400ms báo cáo –

Trả lời

6

---- UPDATE-- -

Tôi nghĩ mình sẽ chia sẻ giải pháp của mình dưới dạng thư viện npm: https://www.npmjs.com/package/jpeg-web-worker. Nó giải thích cách khai thác công nhân web được cung cấp để thực hiện việc nâng hạng nặng cho bạn.

---------------------

tôi nhận được một giải pháp mà làm việc cho tôi, đẩy nhanh tiến độ ứng dụng và khả năng đáp ứng của trang trong khi vẫn tạo ra những hình ảnh mới.

Đây là mã ứng dụng:

App

var canvas = $('#myCanvas')[0]; 
var context = canvas.getContext('2d'); 
var imageData = context.getImageData(0, 0, canvas.width, canvas.height); 
var worker = new Worker('myWorker.js'); 
worker.postMessage({ 
    image: imageData 
}); 
worker.onmessage = function(e) { 
    var blob = new Blob([e.data.data], {type: 'image/jpeg'}); 
    // use blob 
} 

Và đây là mã nhân viên:

Worker

this.onmessage = function(e) { 
    var jpgInfo = encode(e.data.image, 50); 
    this.postMessage(jpgInfo); 
} 

function encode() { ... } // ported from jpeg-js 

Rõ ràng, bu lk của câu trả lời này đến từ hàm encode. Chức năng này đã được sửa đổi từ mô-đun npm jpeg-js và cụ thể hơn là tệp encoder.js. Tôi đã chuyển chức năng mã hóa bằng cách sao chép toàn bộ tệp encoder.js vào myWorker.js của tôi. Nó không phải là nhỏ nhưng nó cũng rất tự chứa mà làm cho nó dễ dàng. Vấn đề duy nhất tôi đã để lại là sửa đổi mã để nó hoạt động bên ngoài môi trường node.js mà nó được xây dựng cho.

này hóa ra là tương đối dễ dàng:

  1. Chuyển đổi "const" khai báo biến để "var"
  2. Loại bỏ tham chiếu đến Buffer. Đây là một quá trình hai bước. Đầu tiên, loại bỏ định nghĩa atob (vì nó không cần thiết) ở trên cùng. Thứ hai, trả lại new Unit8Array ở cuối hàm this.encode. Phiên bản hiện tại thực sự đã nhận xét này ngay trên tham chiếu bộ đệm. Chỉ cần sử dụng một và loại bỏ tất cả mọi thứ bên dưới.
  3. Xóa tham chiếu đến mô-đun.export. Điều này dễ dàng như việc xóa bỏ dòng đó, vì chúng ta chỉ cần hàm này trong tệp này.

Tôi không có phép đo thời gian chính xác nhưng nó đã đi từ ~ 10 giây thời gian trễ khi hình ảnh được tạo thành dưới một giây thời gian trễ. Tôi đang sử dụng "thời gian trễ" ở đây để có nghĩa là hiệu suất chậm chạp trong khi sử dụng trang.

Các vấn đề liên quan