Phloto: Xây dựng công cụ quản lý dòng chụp ảnh cá nhân tối ưu
Tác giả đã tự xây dựng một công cụ tên là "phloto" để giải quyết các vấn đề trong quy trình xử lý ảnh từ tệp RAW đến bản xuất bản web. Bài viết chia sẻ về kỹ thuật xử lý siêu dữ liệu, chuyển mã hình ảnh và việc sử dụng htmx để tạo trải nghiệm người dùng mượt mà.

Gần đây, tôi bắt đầu chụp ảnh nhiều hơn và công khai chúng tại trang cá nhân. Tuy nhiên, tôi không hài lòng với quy trình hiện tại để gắn thẻ (tag), mã hóa và triển khai những bức ảnh này lên trang web của mình. Do đó, tôi đã viết một chương trình phần mềm dành cho nhu cầu cá nhân (houseplant software) để giải quyết vấn đề này. Nếu bạn quan tâm, có thể xem mã nguồn tại đây, nhưng xin lưu ý rằng nó được thiết kế chủ yếu để phục vụ riêng tôi.
Giao diện thư viện ảnh trong phloto, chế độ sáng
Quy trình phát triển ảnh kỹ thuật số
Khi tôi xử lý một bức ảnh, tôi thường trải qua các bước sau:
- Chụp ảnh: Máy ảnh ghi lại một tệp RAW chứa dữ liệu từ cảm biến hình ảnh.
- Nhúng siêu dữ liệu (Metadata): Máy ảnh nhúng thông tin như mẫu máy, ống kính, thời gian, khẩu độ và tốc độ màn trập. Tệp RAW này chứa nhiều dữ liệu hơn những gì chúng ta thường thấy trên web.
- Phát triển tệp RAW: Sử dụng các phần mềm như Darktable hoặc RAWPower, tôi xử lý ảnh. Sau khi sàng lọc, tôi thực hiện các điều chỉnh như cắt, phơi sáng, cân bằng trắng... Với những ảnh ưng ý, tôi xuất ra một tệp ảnh đã phát triển: định dạng PNG không mất dữ liệu 16-bit. Những tệp này rất lớn, trong một số trường hợp hơn 100MB.
- Chuyển đổi ảnh cho web: Tệp PNG không mất dữ liệu tốt cho lưu trữ, nhưng với web, tôi cần thứ gì đó nhỏ hơn và không yêu cầu tính "không mất dữ liệu". Tôi chuyển mã ảnh sang định dạng WebP an toàn cho web. Tôi cũng tạo ra các phiên bản thu nhỏ. Hình ảnh "nổi bật" trong danh sách bài viết hiển thị nhỏ hơn nhiều so với bản gốc, nên tại sao phải lãng phí băng thông để gửi các bit thừa? Các phiên bản web cũng cần có siêu dữ liệu được lọc. Tôi muốn gắn thẻ GPS cho ảnh để sử dụng cá nhân, nhưng không muốn đưa tọa độ sân sau nhà mình lên trang web công cộng.
- Viết chú thích và văn bản thay thế (alt-text): Những nội dung này đi vào trang album, nhưng tôi cố gắng nhúng chúng dưới dạng các trường siêu dữ liệu bổ sung vào ảnh.
Các vấn đề thúc đẩy nhu cầu đổi mới
Trước khi viết phloto, quy trình của tôi là thực hiện bước (1) với máy ảnh, bước (2) với RAWPower, bước (3) với bộ lọc ảnh của Hugo, và bước (4) trong văn bản của trang Hugo. Quy trình này gặp vấn đề ở một vài điểm.
Tính di động
Khi tôi bắt đầu chụp ảnh nhiều hơn, tôi dùng Darktable cho các bước (2) và (4). Đó là một phần mềm rất tuyệt vời! Tuy nhiên, tôi mất một lúc để hiểu quy trình của Darktable và ngay cả khi đã quen, tôi vẫn chỉ dùng một phần nhỏ sức mạnh của nó. Ngay cả khi thoải mái hơn với việc sử dụng Darktable, tôi vẫn thấy việc "mở máy tính" là một rào cản tâm lý để sàng lọc và chỉnh sửa ảnh. Sử dụng máy tính cho nhiệm vụ này khiến việc "xử lý ảnh" trở nên giống như một công việc hay việc vặt.
Cuối cùng tôi đã mua một chiếc iPad đã qua sử dụng với mục đích rõ ràng là dùng để xử lý ảnh khi di chuyển. Nó sống trong túi máy ảnh của tôi thay vì trên bàn làm việc. Không may là iPad không thể chạy Darktable.
Mất siêu dữ liệu
RAWPower và Nitro ở bước (2) không chuyển tất cả siêu dữ liệu từ tệp RAW sang tệp PNG đã phát triển. Chỉ có Darktable (trong số phần mềm tôi đã dùng) cho phép chỉnh sửa các trường siêu dữ liệu tiêu đề và mô tả.
Điều bực mình nhất là Hugo đôi khi thất bại âm thầm trong việc trích xuất siêu dữ liệu Exif từ ảnh PNG và WebP. Tôi không thể "chỉ cần" kéo chú thích (tiêu đề) và văn bản thay thế (mô tả) ra khỏi ảnh, ngay cả khi tôi đã thiết lập nó.
Chuyển mã (Transcoding)
Tôi đang dùng chính Hugo cho bước (3), điều này yêu cầu đưa các tệp đã phát triển vào kho lưu trữ Git của mình. Hãy nhớ rằng, những tệp này chưa được nén; một bộ sưu tập ảnh có thể lên tới hơn 1GB dữ liệu! Các kỹ thuật nén ảnh hiện đại rất tốt trong việc thu nhỏ kích thước tệp, nhưng chúng tốn rất nhiều CPU; chúng mất thời gian. Với hai bộ sưu tập, việc xây dựng lại mất khoảng bốn phút. Tệ hơn là tôi không thiết lập bộ nhớ đệm của Hugo đúng cách, nên hầu như mọi lần xây dựng đều mất lâu như vậy.
Giới thiệu Phloto
Tôi đặt ra các yêu cầu sau:
- Dựa trên nền web: Máy chủ cần có thể truy cập được từ iPad, nơi tôi phát triển ảnh (bước 2), và từ máy tính nơi tôi thực hiện thay đổi cuối cùng cho trang web.
- Chỉnh sửa tiêu đề và mô tả Exif: Tôi muốn xử lý chú thích và văn bản thay thế như một bước "ảnh", không phải bước "web".
- Chuyển mã với siêu dữ liệu Exif đã lọc: Tôi muốn thiết lập các thẻ Exif "an toàn cho công chúng" ngay từ đầu và có mã do tôi kiểm soát thực hiện việc lọc. Tôi muốn thực hiện chuyển mã khoảng một lần, thay vì lãng phí chu kỳ CPU dư thừa.
Phloto thực hiện được các điều trên. Nó là một hỗn hợp của các mã kết dính chưa được kiểm tra giữa máy chủ HTTP hyper, bộ giải mã ảnh và zenwebp, và bản fork của tôi từ thư viện kamadak-exif. Đây là phần mềm "houseplant", không có nỗ lực nào để phù hợp với bất kỳ ai ngoài tôi. Vì vậy, bạn biết đấy, đừng dùng nó. Nhưng nó có một số thủ thuật thú vị; hãy đọc tiếp để tìm cảm hứng!
Ảnh mẫu được xử lý bởi phloto
Chỉnh sửa siêu dữ liệu không phá hủy
Hầu hết phần mềm phát triển RAW sử dụng "chỉnh sửa không phá hủy": chúng không bao giờ sửa đổi tệp RAW. Thay vào đó, chúng ghi một tệp "sidecar" (thường ở định dạng XMP) mô tả các sửa đổi/ diễn giải nào sẽ áp dụng cho dữ liệu RAW. Phần mềm có thể "phát lại" RAW + XMP để nhận tệp đã phát triển (PNG).
Tôi muốn phloto cũng tương tự, coi các tệp RAW và đã phát triển là chỉ đọc. Nhưng tôi không muốn xử lý XMP, cũng không muốn duy trì cơ sở dữ liệu (như Darktable làm).
Thủ thuật của phloto là đọc lại siêu dữ liệu, theo thứ tự ưu tiên, từ mỗi trong ba tệp:
- Tệp web hiện có (nếu có)
- Ảnh đã phát triển (PNG)
- Tệp RAW
Giá trị có ưu tiên cao nhất sẽ được giữ lại, tức là giá trị đầu tiên được đọc trong danh sách trên. Khi tôi cập nhật siêu dữ liệu, phloto ghi ra một tệp web mới — vì vậy giá trị mới có ưu tiên cao nhất.
Nhìn lướt container để tránh chuyển mã thừa
Trong triển khai ban đầu, phloto mã hóa lại mỗi lần siêu dữ liệu thay đổi. Điều này "Không Tốt Lắm", vì chuyển mã lại dẫn đến công việc dư thừa... và mất rất nhiều thời gian!
May mắn là tôi đã có một trình phân tích cú pháp WebP gần hoàn chỉnh từ giai đoạn trước của dự án. Nhờ đó, phloto có thể mở container WebP mà không thực sự giải mã ảnh, chỉ thay thế dữ liệu Exif và ghi lại tệp đã cập nhật.
Bây giờ vấn đề của tôi là các bản cập nhật quá nhanh — phản hồi trực quan "tôi đang cập nhật này" biến mất trước khi tôi kịp nhìn thấy!
Lưu ý rằng một ảnh có thể được chuyển mã lại nếu tệp đã phát triển (PNG) mới hơn tệp web (WebP). Nếu tôi muốn phát triển lại một ảnh, tôi vẫn có thể làm được vậy.
htmx tuyệt vời như thế nào
Tôi đã muốn dùng htmx một thời gian nhưng chưa có dự án nào thực sự cần nó. Mọi thứ tôi làm đều hoàn toàn ở phía máy chủ hoặc hoàn toàn ở phía máy khách. Đây là cơ hội tuyệt vời để thử nó!
htmx xử lý một vài thứ làm cho giao diện nhanh và tương tác:
Lần đầu tiên một ảnh được tải, phloto chưa có phiên bản thân thiện với web của nó. phloto khởi chạy một chuyển mã nền... và thông qua một chút htmx, nó yêu cầu trình duyệt tải lại đoạn HTML quanh ảnh.
Đây là một lần tải (load poll) của htmx. Trong khi chuyển mã đang diễn ra, trình giữ chỗ (placeholder) và chỉ thị poll vẫn ở đó. Khi chuyển mã xong, phloto phục vụ một đoạn HTML mới, không có poll — và với một chỉ báo văn bản "webp", cho biết chuyển mã đã hoàn thành.
Cập nhật siêu dữ liệu chạy thông qua một phần tử form được xử lý bởi htmx. Khi gửi form hoàn tất, phloto phục vụ lại một đoạn HTML thay thế form hiện có, với dữ liệu được đọc lại từ tệp vừa ghi, mang lại xác nhận rằng cập nhật đã hoàn thành.
Giao diện thư viện ảnh trong phloto, chế độ tối
Các bước tiếp theo
Tôi thấy mình bối rối không biết siêu dữ liệu có cập nhật chưa hay không, ví dụ như khi tôi nhấn "submit". Có lẽ tôi sẽ muốn thêm một chỉ báo cho việc này.
Phloto có thể nhanh hơn một chút khi liệt kê nội dung của các thư mục lớn. Mỗi lần liệt kê trang album có nhiều cuộc gọi "tìm và phân tích nguồn cho ảnh này"; việc lưu chúng vào bộ nhớ đệm có thể sẽ tăng tốc độ tốt.
Tôi có thể muốn hiển thị các số liệu, ví dụ như "có bao nhiêu chuyển mã đang chạy".
Vẫn còn lỗi chưa được giải quyết là Hugo không thể đọc siêu dữ liệu từ một số tệp; tôi có thể cần sửa lỗi này, nếu vấn đề nằm ở phloto hoặc trình chỉnh sửa webp của tôi. Nhưng tôi có thể bỏ qua điều này, bằng cách cho phloto tạo nguồn markdown (với alt-text và chú thích được điền sẵn), hoặc chuyển trang web của tôi khỏi Hugo.
Tuy nhiên, nói như vậy, phloto đã đáp ứng các yêu cầu mà tôi tìm kiếm. Ngoài một chút chỉnh sửa kiểu, và tùy chọn dọn dẹp tổ chức mã, tôi nghĩ không có gì nhiều để thêm nữa.


