2012-04-18 51 views
9

Tôi cần chia tỷ lệ hình ảnh thành dạng mảng trong Công nhân Web. Nếu tôi ở bên ngoài một nhân viên web, tôi có thể sử dụng canvas và drawImage để sao chép các phần nhất định của hình ảnh hoặc chia tỷ lệ hình ảnh đó.Nhân viên web và chia tỷ lệ hình ảnh

Có vẻ như trong một nhân viên web, tôi không thể sử dụng canvas để tôi có thể làm gì? Có thư viện Javascript thuần túy nào có thể giúp tôi không?

Cảm ơn rất nhiều trước.

+0

Hey người đàn ông tôi cần phải làm như vậy, bạn đã findf bất kỳ imageData/ByteArray RGBA chồng chéo lên nhau và mở rộng thư viện hoặc chức năng? – Noitidart

Trả lời

15

Việc chia tỷ lệ có thể được thực hiện theo nhiều cách khác nhau, nhưng tất cả chúng đều đun sôi xuống để xóa hoặc tạo pixel từ hình ảnh. Vì hình ảnh về cơ bản là ma trận (được đổi kích thước thành mảng) của giá trị pixel, bạn có thể xem xét phóng to hình ảnh như mở rộng mảng đó và điền vào chỗ trống và thu nhỏ hình ảnh như thu hẹp mảng bằng cách để lại giá trị.

Điều đó đang được nói, thường không khó để viết chức năng tỷ lệ của riêng bạn trong JavaScript hoạt động trên các mảng. Vì tôi hiểu rằng bạn đã có các hình ảnh dưới dạng một mảng JavaScript, bạn có thể chuyển mảng đó trong một thông báo tới Web Worker, mở rộng phạm vi chức năng quy mô của bạn và gửi mảng được chia tỷ lệ về chủ đề chính.

Về mặt biểu diễn, tôi khuyên bạn nên sử dụng Uint8ClampedArray được thiết kế cho hình ảnh được mã hóa RGBA (màu, với kênh alpha) và hiệu quả hơn các mảng JavaScript bình thường. Bạn cũng có thể dễ dàng gửi các đối tượng Uint8ClampedArray trong các thông báo tới Web Worker của bạn, do đó sẽ không có vấn đề gì. Một lợi ích khác là một Uint8ClampedArray được sử dụng trong datatype ImageData (sau khi thay thế CanvasPixelArray) của Canvas API. Điều này có nghĩa là nó khá dễ dàng để vẽ hình ảnh thu nhỏ của bạn trở lại trên Canvas (nếu đó là những gì bạn muốn), đơn giản bằng cách lấy ImageData hiện tại của khung cảnh '2D' bằng cách sử dụng ctx.getImageData() và thay đổi thuộc tính dữ liệu của nó. Đối tượng Uint8ClampedArray.

Nhân tiện, nếu bạn chưa có hình ảnh làm mảng, bạn có thể sử dụng cùng một phương pháp. Đầu tiên vẽ hình ảnh trên khung hình và sau đó sử dụng thuộc tính dữ liệu của đối tượng ImageData hiện tại để truy xuất hình ảnh trong một Uint8ClampedArray.

Về phương pháp chia tỷ lệ để nâng cao hình ảnh, về cơ bản có hai thành phần mà bạn cần triển khai. Điều đầu tiên là chia các pixel đã biết (nghĩa là các pixel từ hình ảnh bạn đang co giãn) trên mảng mới lớn hơn mà bạn đã tạo. Một cách rõ ràng là phân chia đồng đều tất cả các pixel trên không gian. Ví dụ: nếu bạn đang làm chiều rộng của hình ảnh rộng gấp đôi, bạn chỉ muốn bỏ qua một vị trí sau mỗi pixel để khoảng trắng ở giữa.

Thành phần thứ hai sau đó điền vào các khoảng trống đó, điều này có thể hơi đơn giản hơn. Tuy nhiên, có một số là khá dễ dàng. (Mặt khác, nếu bạn có kiến ​​thức về Computer Vision hoặc Image Processing, bạn có thể muốn xem xét một số phương pháp nâng cao hơn.) Một phương pháp dễ dàng và hơi rõ ràng là nội suy từng vị trí điểm ảnh không xác định bằng cách sử dụng hàng xóm gần nhất (tức là gần nhất giá trị pixel được biết) bằng cách sao chép màu của pixel đã biết. Điều này thường dẫn đến hiệu ứng của các pixel lớn hơn (các khối lớn hơn cùng màu) khi bạn chia tỷ lệ hình ảnh quá nhiều. Thay vì sao chép màu của pixel gần nhất, bạn cũng có thể lấy trung bình một số pixel đã biết gần đó. Thậm chí có thể kết hợp với trọng lượng là bạn làm cho các pixel gần hơn đếm nhiều hơn trung bình so với các pixel ở xa hơn. Các phương pháp khác bao gồm làm mờ hình ảnh bằng cách sử dụng Gaussians. Nếu bạn muốn tìm ra phương pháp nào là tốt nhất cho ứng dụng của bạn, hãy xem một số trang về nội suy ảnh. Tất nhiên, hãy nhớ rằng mở rộng quy mô luôn có nghĩa là điền vào những thứ không thực sự ở đó. Mà sẽ luôn luôn xấu nếu bạn làm điều đó quá nhiều.

Theo như quy mô giảm xuống có liên quan, người ta thường chỉ xóa pixel bằng cách chỉ chuyển một lựa chọn pixel từ mảng hiện tại sang mảng nhỏ hơn.Ví dụ nếu bạn muốn làm cho hình ảnh có kích thước nhỏ gấp đôi, bạn gần như lặp qua mảng hiện tại với các bước 2 (Điều này phụ thuộc một chút vào kích thước của hình ảnh, thậm chí là lẻ hoặc đại diện cho bạn sử dụng). Có những phương pháp làm điều này thậm chí còn tốt hơn bằng cách loại bỏ những điểm ảnh có thể bị bỏ sót nhiều nhất. Nhưng tôi không biết đủ về chúng.

Nhân tiện, tất cả điều này thực tế không liên quan đến nhân viên web. Bạn sẽ làm điều đó theo cách tương tự nếu bạn muốn chia tỷ lệ hình ảnh trong JavaScript trên chuỗi chính. Hoặc bằng bất kỳ ngôn ngữ nào khác cho vấn đề đó. Tuy nhiên, các Web Worker là một cách rất hay để thực hiện các phép tính này trên một luồng riêng biệt thay vì trên chuỗi giao diện người dùng, điều đó có nghĩa rằng chính trang web đó dường như không phản hồi. Tuy nhiên, như bạn đã nói, tất cả mọi thứ liên quan đến phần tử canvas cần phải được thực hiện trên luồng chính, nhưng các mảng nhân rộng có thể được thực hiện ở bất kỳ đâu.

Ngoài ra, tôi chắc chắn có các thư viện JavaScript có thể thực hiện việc này cho bạn và tùy thuộc vào phương pháp của chúng, bạn cũng có thể tải chúng trong Công việc Web của bạn bằng cách sử dụng importScripts. Nhưng tôi sẽ nói rằng trong trường hợp này, nó có thể dễ dàng hơn và vui hơn rất nhiều khi tự mình viết nó và làm cho nó được thiết kế riêng cho mục đích của bạn.

Và tùy thuộc vào mức độ kỹ năng lập trình nâng cao và tốc độ bạn cần mở rộng, bạn luôn có thể thử thực hiện việc này trên GPU thay vì trên CPU bằng WebGL. Nhưng điều đó có vẻ hơi quá mức trong trường hợp này. Ngoài ra, bạn có thể cố gắng cắt hình ảnh của bạn thành nhiều phần và cố gắng mở rộng các phần riêng biệt trên một số Công nhân Web làm cho nó đa luồng. Mặc dù nó chắc chắn không tầm thường để kết hợp các phần sau này. Có lẽ đa luồng có ý nghĩa hơn khi bạn có nhiều hình ảnh cần được thu nhỏ ở phía máy khách.

Tất cả đều phụ thuộc vào ứng dụng của bạn, hình ảnh và kỹ năng và mong muốn của riêng bạn.

Dù sao, tôi hy vọng rằng câu trả lời gần như là câu hỏi của bạn.

+0

Cảm ơn rất nhiều vì tất cả các chi tiết. Và một thực hiện javascript đơn giản một mình sẽ là đủ trong trường hợp của tôi. –

+1

người đàn ông ... đó là câu trả lời – Jeremythuff

5

Tôi cảm thấy một số chi tiết cụ thể về câu trả lời của mslatour, vì tôi đã dành 6 giờ để tìm ra cách "... đơn giản ... thay đổi thuộc tính dữ liệu của nó thành đối tượng Uint8ClampedArray được thu nhỏ". Để thực hiện việc này:

① Gửi lại mảng của bạn từ nhân viên web. Sử dụng biểu mẫu:

self.postMessage(bufferToReturn, [bufferToReturn]); 

để chuyển bộ đệm của bạn đến và từ nhân viên web mà không cần sao chép, nếu bạn không muốn. (Đó là nhanh hơn theo cách này.) (Có some MDN documentation, nhưng tôi không thể liên kết với nó như tôi ra khỏi đại diện. Xin lỗi) Dù sao, bạn cũng có thể đặt bufferToReturn đầu tiên bên trong danh sách hoặc bản đồ, như thế này:

self.postMessage({buffer:bufferToReturn, width:500, height:500}, [bufferToReturn]); 

Bạn sử dụng cái gì đó như

webWorker.addEventListener('message', function(event) {your code here}) 

để nghe cho một tin nhắn đăng. (Trong trường hợp này, các sự kiện được đăng là từ nhân viên web và sự kiện đang nghe là trong mã JS bình thường của bạn. Nó hoạt động theo cách khác, chỉ cần chuyển các biến 'self' và 'webWorker' xung quanh.)

② Trong Javascript bên trình duyệt của bạn (trái ngược với phía người lao động), bạn có thể sử dụng imageData .data.set() để "đơn giản" thay đổi thuộc tính dữ liệu và đưa nó trở lại trong canvas.

var imageData = context2d.createImageData(width, height); 
imageData.data.set(new Uint8ClampedArray(bufferToReturn)); 
context2d.putImageData(imageData, x_offset, y_offset); 

Tôi muốn cảm ơn hacks.mozilla.org để cảnh báo tôi về sự tồn tại của phương thức data.set().

p.s. Tôi không biết bất kỳ thư viện nào để trợ giúp điều này…. Lấy làm tiếc.

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