+8

Tại sao ảnh của iPhone luôn mượt và đẹp hơn của Android

1. Nguồn

Why the image quality of iPhone is much better than Android?

2. Động cơ

Ngồi tranh luận với các ông anh và ông em trong nhóm về vấn đề performace giữa Android và iOS, nhớ lại chủ đề khá hay này đã từng đọc trên qiita và quyết định dịch lại cho mọi người.

3. Bài viết

Nếu là một fan công nghệ, các bạn sẽ thấy ngày ngày vẫn có những bài so sánh giữa máy Android và iPhone. Chúng ta không thể tóm gọn lại là thứ nào tốt hơn, tuy nhiên có một điều mà ai cũng ngầm hiểu chính là chất lượng ảnh trên Android luôn kém hơn khi so sánh với iPhone. Không cần quan tâm bạn sử dụng Facebook, Twitter hay Instagram, sau khi bạn chụp một tấm ảnh, thêm filter vào rồi chia sẻ lên mạng xã hội, những tấm ảnh này nếu được tạo ra bởi máy Android sẽ không mịn. Vậy tại sao?

Nhóm chúng tôi đã làm việc trong vấn đề này trong năm vừa rồi. Sau khi tiến hành nghiên cứ rất sâu, chúng tôi đã tìm thấy một lỗi nhỏ được tạo ra bởi Google. Mặc dù gọi là nhỏ, tuy nhiên độ ảnh hưởng của nó rất lớn (trên tất cả Android Apps liên quan tới hình ảnh) và vẫn tiếp tục tới tận ngày nay.

Vấn đề chính là libjpeg. Chúng ta đều biết rằng libjpeg được sử dụng rộng rãi với open source JPEG library. Android cũng sử dụng libjpeg để nén ảnh. Sau khi chọc sâu vào source code của Android, chúng tôi đã nhận ra 1 điều đó là thay vì sử dụng libjpeg trực tiếp, Android được dựa trên một engine ảnh open source có tên Skia. Skia là một engine tuyệt vời được duy trì bởi chính Google, tất cả chức năng ảnh đều được implement trong engine này, và nó được sử dụng rộng rãi bởi Google và các sản phẩm của công ty khác (ví dụ: Chrome, Firefox, Android..). Skia đóng gói khá tốt libjpeg, bạn có thể dễ dàng develop tiện ích ảnh dựa trên engine này.

Khi sử dụng libjpeg để nén ảnh, optimize_coding là một parameter rất quan trọng. Trong tài liệu libjpeg.doc, chúng tôi tìm thấy đoạn giới thiệu sau về parameter này:

boolean optimize_coding
	Khi TRUE sẽ khiến compressor(máy nén) tính toán bảng coding Huffman tối ưu cho ảnh. Điều này yêu cầu việc pass thêm trên data cho nên sẽ tốn kha khá thời gian và bộ nhớ.
    Default sẽ là FALSE và thông báo cho compressor là hãy sử dụng bảng Huffman default hoặc được cung cấp.
    Trong hầu hết các trường hợp, các bảng tối ưu chỉ tiết kiệm được 1 vài phần trăm của kích cỡ file so với bảng default. Hãy lưu ý là khi giá trị là TRUE, bạn không cần phải cung cấp bảng Huffman và nếu bạn có cung cấp thì cũng sẽ bị ghi đè lên.

Theo tài liệu trên chúng ta cũng có thể thấy nếu cài đặt giá trị optimize_coding là TRUE sẽ tốn thời gian và bộ nhớ, cho nên default trong libjpeg là FALSE.

Mọi thứ có vẻ rất ổn về tài liệu, và thực tế thì libjpeg hoạt động rất ổn định. Tuy nhiên rất nhiều người quên rằng tài liệu này đã được viết vào 10 năm trước rồi. Tại thời điểm đó, khả năng tính toán và bộ nhớ bị giới hạn rất nhiều. Với những chiếc điện thoại và máy vi tính đời mới hiện nay, đó không phải là vấn đề nữa. Ngược lại, chúng ta quan tâm tới chất lượng hình ảnh (màn hình retina) và kích cỡ ảnh (cloud service).

Những kỹ sư Google làm việc trong dự án Skia đã không set parameter này, chính vì thế optimize_coding trong Skia luôn được giữ là FALSE, ngoài ra Skia cũng che giá trị cài đặt này đi và bạn không thể thay đổi nó. Đây đã trở thành một vấn đề rất lớn và chúng ta phải chịu đựng sử dụng hình ảnh chất lượng thấp mà kích cỡ file lại lớn.

Nhóm chúng tôi đã test optimize_coding trên rất nhiều hình ảnh khác nhau. Nếu bạn muốn chất lượng của hình ảnh sau khi nén được giữ nguyên, khi optimize_coding là FALSE thì kích cỡ file sẽ lớn hơn 5~10 lần khi so với optimize_coding là TRUE. Sự khác biệt này là rất rõ rệt.

Chúng tôi cũng đã so sánh việc nén jpeg giữa iOS và Android (cả 2 đều giấu optimize_coding parameter). Với cùng các ảnh gốc, nếu bận muốn chất lượng giống nhau thì bạn cần kích cỡ gấp 5~10 lần trên Androdi khi so với iOS.

Kết quả đã rõ ràng, Apple biết độ quan trọng của optimize_coding và bảng Huffman, trong khi Google không quan tâm tới nó. (Apple sử dụng thuật toán bảng Huffman riêng, không giống như libjpeg hoặc libjpeg-turbo. Dường như Apple đã tinh chỉnh rất nhiều liên quan tới việc nén ảnh.)

Cuối cùng, chúng tôi đã quyết định không sử dụng các chức năng nén JPEG được cung cấp bởi Android, và compile dựa trên native library riêng đã phát triển dựa theo libjpeg-turbo (libjpeg-turbo cũng có cải thiện về performance). Bây giờ chúng tôi đã có thể tiết kiệm 5~10 lần dung lượng ảnh và có chất lượng tốt hơn. Dự án đã thành công tuyệt vời.

Dự án của chúng tôi trên Github: https://github.com/bither


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí