Câu trả lời này được tóm tắt từ Tải ảnh bitmap lớn một cách hiệu quả
, giải thích cách sử dụng inSampleSize để tải phiên bản bitmap thu nhỏ.
Cụ thể , bitmap chia tỷ lệ trước giải thích chi tiết về các phương pháp khác nhau, cách kết hợp chúng và phương pháp nào hiệu quả nhất.
Có ba cách chính để thay đổi kích thước bitmap trên Android có các thuộc tính bộ nhớ khác nhau:
API createScaledBitmap
API này sẽ lấy một bitmap hiện có và tạo một bitmap MỚI với các kích thước chính xác mà bạn đã chọn.
Mặt tích cực, bạn có thể nhận được chính xác kích thước hình ảnh mà bạn đang tìm kiếm (bất kể nó trông như thế nào). Nhưng nhược điểm là API này yêu cầu một bitmap hiện có để hoạt động . Có nghĩa là hình ảnh sẽ phải được tải, giải mã và tạo bitmap trước khi có thể tạo một phiên bản mới, nhỏ hơn. Điều này là lý tưởng về mặt nhận được kích thước chính xác của bạn, nhưng khủng khiếp về mặt bộ nhớ bổ sung. Do đó, đây là một công cụ phá vỡ thỏa thuận đối với hầu hết các nhà phát triển ứng dụng, những người có xu hướng quan tâm đến trí nhớ
cờ inSampleSize
BitmapFactory.Options
có một thuộc tính được lưu ý là inSampleSize
sẽ thay đổi kích thước hình ảnh của bạn trong khi giải mã nó, để tránh phải giải mã thành một bitmap tạm thời. Giá trị số nguyên này được sử dụng ở đây sẽ tải một hình ảnh ở kích thước giảm 1 / x. Ví dụ: đặt inSampleSize
thành 2 trả về một hình ảnh có kích thước bằng một nửa và Đặt thành 4 trả về hình ảnh có kích thước 1/4. Về cơ bản, kích thước hình ảnh sẽ luôn nhỏ hơn kích thước nguồn của bạn một số lũy thừa.
Từ góc độ bộ nhớ, sử dụng inSampleSize
là một hoạt động thực sự nhanh chóng. Một cách hiệu quả, nó sẽ chỉ giải mã mọi pixel thứ X của hình ảnh thành ảnh bitmap kết quả của bạn. Tuy nhiên, có hai vấn đề chính inSampleSize
:
Nó không cung cấp cho bạn độ phân giải chính xác . Nó chỉ làm giảm kích thước bitmap của bạn bằng một số sức mạnh của 2.
Nó không tạo ra chất lượng tốt nhất thay đổi kích thước . Hầu hết các bộ lọc thay đổi kích thước tạo ra hình ảnh đẹp bằng cách đọc các khối pixel, sau đó cân chúng để tạo ra pixel được thay đổi kích thước được đề cập. inSampleSize
tránh tất cả những điều này bằng cách chỉ đọc mỗi vài pixel. Kết quả là khá hiệu quả và bộ nhớ thấp, nhưng chất lượng bị ảnh hưởng.
Nếu bạn chỉ giải quyết việc thu nhỏ hình ảnh của mình theo một số kích thước pow2 và việc lọc không phải là vấn đề, thì bạn không thể tìm thấy phương pháp hiệu quả về bộ nhớ (hoặc hiệu suất hiệu quả) hơn inSampleSize
.
cờ inScaled, inDensity, inTargetDensity
Nếu bạn cần phải mở rộng quy mô một hình ảnh đến một kích thước mà không bằng một sức mạnh của hai, sau đó bạn sẽ cần inScaled
, inDensity
và inTargetDensity
cờ của BitmapOptions
. Khi inScaled
cờ đã được đặt, hệ thống sẽ lấy giá trị tỷ lệ để áp dụng cho bitmap của bạn bằng cách chia cho inTargetDensity
các inDensity
giá trị.
mBitmapOptions.inScaled = true;
mBitmapOptions.inDensity = srcWidth;
mBitmapOptions.inTargetDensity = dstWidth;
// will load & resize the image to be 1/inSampleSize dimensions
mCurrentBitmap = BitmapFactory.decodeResources(getResources(),
mImageIDs, mBitmapOptions);
Sử dụng phương pháp này sẽ thay đổi kích thước hình ảnh của bạn và cũng áp dụng 'bộ lọc thay đổi kích thước' cho nó, nghĩa là, kết quả cuối cùng sẽ đẹp hơn vì một số phép toán bổ sung đã được tính đến trong bước thay đổi kích thước. Nhưng được cảnh báo: bước lọc bổ sung đó, tốn thêm thời gian xử lý và có thể nhanh chóng thêm vào các hình ảnh lớn, dẫn đến việc thay đổi kích thước chậm và phân bổ thêm bộ nhớ cho chính bộ lọc.
Nói chung không phải là ý kiến hay khi áp dụng kỹ thuật này cho một hình ảnh lớn hơn đáng kể so với kích thước mong muốn của bạn, do chi phí lọc bổ sung.
Kết hợp ma thuật
Từ góc độ bộ nhớ và hiệu suất, bạn có thể kết hợp các tùy chọn này để có kết quả tốt nhất. (thiết lập inSampleSize
, inScaled
, inDensity
và inTargetDensity
cờ)
inSampleSize
trước tiên sẽ được áp dụng cho hình ảnh, đưa nó lên kích thước LỚN hơn gấp hai lần tiếp theo so với kích thước mục tiêu của bạn. Sau đó, inDensity
& inTargetDensity
được sử dụng để chia tỷ lệ kết quả theo kích thước chính xác mà bạn muốn, áp dụng thao tác lọc để làm sạch hình ảnh.
Kết hợp hai thao tác này là một thao tác nhanh hơn nhiều, vì inSampleSize
bước này sẽ giảm số lượng pixel mà bước dựa trên Mật độ kết quả sẽ cần áp dụng bộ lọc thay đổi kích thước.
mBitmapOptions.inScaled = true;
mBitmapOptions.inSampleSize = 4;
mBitmapOptions.inDensity = srcWidth;
mBitmapOptions.inTargetDensity = dstWidth * mBitmapOptions.inSampleSize;
// will load & resize the image to be 1/inSampleSize dimensions
mCurrentBitmap = BitmapFactory.decodeFile(fileName, mBitmapOptions);
Nếu bạn cần điều chỉnh một hình ảnh với kích thước cụ thể và một số bộ lọc đẹp hơn, thì kỹ thuật này là cầu nối tốt nhất để có được kích thước phù hợp, nhưng được thực hiện trong một thao tác nhanh, ít bộ nhớ.
Nhận kích thước hình ảnh
Nhận kích thước hình ảnh mà không cần giải mã toàn bộ hình ảnh Để thay đổi kích thước ảnh bitmap của bạn, bạn sẽ cần biết các kích thước đến. Bạn có thể sử dụng inJustDecodeBounds
cờ để giúp bạn nhận được kích thước của hình ảnh, bạn cần thực sự giải mã dữ liệu pixel.
// Decode just the boundaries
mBitmapOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(fileName, mBitmapOptions);
srcWidth = mBitmapOptions.outWidth;
srcHeight = mBitmapOptions.outHeight;
//now go resize the image to the size you want
Bạn có thể sử dụng cờ này để giải mã kích thước trước tiên, sau đó tính toán các giá trị thích hợp để chia tỷ lệ theo độ phân giải mục tiêu của bạn.