Bản đồ Bitmap quá lớn để được tải lên thành một kết cấu


154

Tôi đang tải một bitmap vào ImageView và thấy lỗi này. Tôi thu thập giới hạn này liên quan đến giới hạn kích thước cho kết cấu phần cứng OpenGL (2048x2048). Hình ảnh tôi cần tải là hình ảnh có độ phóng đại cao khoảng 4.000 pixel.

Tôi đã thử tắt tăng tốc phần cứng trong bảng kê khai, nhưng không có niềm vui.

    <application
        android:hardwareAccelerated="false"
        ....
        >

Có thể tải hình ảnh lớn hơn 2048 pixel vào ImageView không?


1
Đối với bất kỳ ai đang tìm kiếm ở đây, đừng quên đặt hình ảnh của bạn trong chế độ xem cuộn nếu bạn muốn nó có thể cuộn được. Điều đó sẽ thoát khỏi lỗi. Tôi đã lãng phí một thời gian trước khi nhận ra đó là vấn đề của mình.
Jason Ridge

Đối với bất kỳ ai muốn hiển thị hình ảnh lớn mà vẫn giữ được chất lượng hình ảnh, hãy tham khảo thư viện trong câu trả lời @stoefln bên dưới. Tôi đã sử dụng nó và đáng để thử. Chắc chắn tốt hơn so với inSampleSizecách tiếp cận.
Mahendra Liya

1
@Joe Thổi câu trả lời hiện tại không hoạt động trong trường hợp của bạn? Nếu không thì xin hãy giải thích về vấn đề bạn gặp phải trong bối cảnh của câu hỏi này?
Pravin Divraniya

1
hey @ VC.One - đó là một điều kỳ lạ để làm việc về người đàn ông của tôi. Tôi nên nhấp vào "Thưởng câu trả lời hiện có". Không ai bận tâm nhấn nút "tốt nhất" trên cửa sổ bật lên SO đó, bởi vì điều đó thật ngớ ngẩn :) Bây giờ tất cả đã được giải quyết khi tôi nhấp vào tiền thưởng. Chúc mừng !!
Fattie

1
Tôi cố gắng luôn trả tiền thưởng (tôi không thích thu thập điểm). Tôi đoán, nếu bạn nhấp vào hồ sơ của tôi, sau đó tiền thưởng, @ VC.One bạn sẽ thấy nhiều QA thực sự tuyệt vời từ SO trong những năm qua !!!!!!!!!!!!!!!
Fattie

Câu trả lời:


48

Tất cả kết xuất đều dựa trên OpenGL, do đó, bạn không thể vượt quá giới hạn này ( GL_MAX_TEXTURE_SIZEtùy thuộc vào thiết bị, nhưng mức tối thiểu là 2048x2048, do đó, bất kỳ hình ảnh nào thấp hơn 2048x2048 đều phù hợp).

Với những hình ảnh lớn như vậy, nếu bạn muốn phóng to và trong điện thoại di động, bạn nên thiết lập một hệ thống tương tự như những gì bạn thấy trong google maps chẳng hạn. Với hình ảnh được chia thành nhiều phần, và một số định nghĩa.

Hoặc bạn có thể thu nhỏ hình ảnh trước khi hiển thị nó (xem câu trả lời của user1352407 về câu hỏi này).

Ngoài ra, hãy cẩn thận với thư mục bạn đặt hình ảnh vào, Android có thể tự động phóng to hình ảnh. Hãy xem câu trả lời của Pilot_51 bên dưới về câu hỏi này.


23
Nếu đây là trường hợp, làm thế nào để ứng dụng Thư viện cho phép hiển thị và thao tác hình ảnh được chụp bằng máy ảnh? 2048x2048 chỉ là hình ảnh 4MP và nhiều điện thoại Android chụp ảnh lớn hơn thế này và ứng dụng Thư viện dường như không có vấn đề gì.
Ollie C

3
Bởi vì GL_MAX_TEXTURE_SIZE phụ thuộc vào thiết bị.
jptsetung

24
Điều này thực sự không có ý nghĩa gì. Tôi đã gặp vấn đề tương tự bây giờ - với hình ảnh 1286x835 pixel. VÀ: chỉ trên Galaxy Nexus tôi nhận được thông báo lỗi này và không có hình ảnh! Có vẻ thật nực cười khi một chiếc điện thoại thông minh hàng đầu không thể hiển thị một hình ảnh nhỏ như vậy! HTC Hero của tôi có khả năng hiển thị điều đó! Tôi có thể làm gì?
Zordid

1
Xem câu trả lời của Romain tại đây: stackoverflow.com/questions/7428996/ Khăn
Ben Lee

3
@OllieC Tôi cũng muốn biết làm thế nào các ứng dụng thư viện làm điều đó. Vì vậy, nếu bất cứ ai biết, hoặc có một ví dụ để hiển thị hình ảnh lớn, đó sẽ là tuyệt vời.
Innova

408

Đây không phải là câu trả lời trực tiếp cho câu hỏi (tải hình ảnh> 2048), nhưng là một giải pháp khả thi cho bất kỳ ai gặp lỗi.

Trong trường hợp của tôi, hình ảnh nhỏ hơn 2048 ở cả hai chiều (chính xác là 1280x727) và vấn đề được đặc biệt gặp phải trên Galaxy Nexus. Hình ảnh nằm trong drawablethư mục và không có thư mục nào đủ điều kiện. Android giả định các khả năng rút ra mà không có vòng loại mật độ là mdpi và chia tỷ lệ lên hoặc xuống cho các mật độ khác, trong trường hợp này được tăng lên gấp 2 lần cho xhdpi. Di chuyển hình ảnh thủ phạm drawable-nodpiđể ngăn chặn tỷ lệ giải quyết vấn đề.


3
Tôi đã có vấn đề về bộ nhớ khi cố gắng tải drawables. Đã dành 2 giờ cố gắng để hiểu tại sao điều này đã xảy ra. Cảm ơn câu trả lời gián tiếp.
TrueCoke

16
Đây là câu trả lời đúng và nên được đánh dấu như vậy.
wblaschko

3
Khoảng ba tháng rưỡi nay tôi đã lập trình gần như toàn thời gian trên Android và tôi mới nhận ra điều này. Có vẻ ngu ngốc để làm cho drawablemột drawable-mdpithư mục ẩn . Điều này cũng giải thích lý do tại sao các điểm đánh dấu trên bản đồ tùy chỉnh của tôi trông khủng khiếp (chúng được nâng cấp, sau đó được hạ thấp).
theblang

10
ừ cái quái gì thế! Tôi nghĩ rằng 99% lập trình viên Android nghĩ rằng "drawable" có nghĩa là "không mở rộng quy mô này".
Matt Logan

3
Đây là câu trả lời hữu ích nhất tôi từng thấy, ở bất cứ đâu. Tất cả những gì tôi có thể nói là tôi đang gửi tiền thưởng! CẢM ƠN.
Fattie

105

Tôi đã thu nhỏ hình ảnh theo cách này:

ImageView iv  = (ImageView)waypointListView.findViewById(R.id.waypoint_picker_photo);
Bitmap d = new BitmapDrawable(ctx.getResources() , w.photo.getAbsolutePath()).getBitmap();
int nh = (int) ( d.getHeight() * (512.0 / d.getWidth()) );
Bitmap scaled = Bitmap.createScaledBitmap(d, 512, nh, true);
iv.setImageBitmap(scaled);

2
cảm ơn, createdScaledBitmap rất hữu ích cho tôi để có thể hiển thị một bitmap quá lớn
Boy

Giải quyết vấn đề của tôi .. cảm ơn. Trên thực tế, tôi đã lấy hình ảnh từ máy ảnh và hiển thị trong ImageView trong Samsung Galaxy S4 với 4.4.2
Mitesh Shah

xin lỗi, nhưng tôi không thể phát hiện ra "w" là gì
Bobbelinio

1
Xin lỗi, điều này ctxcó nghĩa là gì?
Ameer Sabith

1
@AmeerSabith trông giống như ctx là một đối tượng Ngữ cảnh (ví dụ Hoạt động đang chạy của bạn)
Matt

34

Thay vì dành hàng giờ đồng hồ để cố gắng viết / gỡ lỗi tất cả mã downsampling này theo cách thủ công, tại sao không sử dụng Picasso? Nó được tạo ra để đối phó với bitmapstất cả các loại và / hoặc kích cỡ.

Tôi đã sử dụng dòng mã đơn này để loại bỏ vấn đề "bitmap quá lớn ...." của mình :

Picasso.load(resourceId).fit().centerCrop().into(imageView);

Sử dụng centreCrop () mà không gọi resize () sẽ dẫn đến IllegalStateException. Lực lượng thư viện để gọi thay đổi kích thước khi sử dụng cây trồng trung tâm.
Zsolt Boldizsár

Điều đó có ý nghĩa hoàn hảo, bởi vì cắt xén ngụ ý rằng bạn đang thay đổi kích thước hình ảnh.
Phileo99

2
Giải pháp nhanh chóng, dễ dàng và đơn giản. Không chắc chắn nếu nó là tốt nhất, nhưng tôi đã có được những gì tôi muốn. Cảm ơn bạn rất nhiều
Nabin

vẫn gặp lỗi tương tự khi sử dụng mục tiêu với Picasso, đối với các hình ảnh có kích thước lớn hơn :(
Narendra Singh

Hãy thử sử dụng phiên bản 2.5.3-SNAPSHOT, có vẻ như bây giờ nó hoạt động chính xác với hình ảnh lớn
Anton Malmygin

20

Bổ sung 2 thuộc tính sau trong ( AndroidManifest.xml) làm việc cho tôi:

android:largeHeap="true"
android:hardwareAccelerated="false"

Điều này đã khắc phục sự cố của tôi trên thiết bị Samsung. Cảm ơn
Hitesh Bisht

16

Thay đổi tập tin hình ảnh thành drawable-nodpithư mục từ drawablethư mục làm việc cho tôi.


Điều này sẽ ngăn Android cố gắng tự động chia tỷ lệ hình ảnh dựa trên kích thước và mật độ màn hình của thiết bị; đây là lý do tại sao giải pháp này hoạt động. Android sẽ cố gắng tự động chia tỷ lệ bất cứ thứ gì trong drawablethư mục.
Chris Cirefice

10

Tôi đã sử dụng Picasso và có cùng một vấn đề. hình ảnh quá lớn ít nhất là về kích thước, chiều rộng hoặc chiều cao. cuối cùng tôi đã tìm thấy giải pháp ở đây. bạn có thể thu nhỏ hình ảnh lớn xuống theo kích thước hiển thị và cũng giữ tỷ lệ khung hình:

    public Point getDisplaySize(Display display) {
    Point size = new Point();

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
        display.getSize(size);
    } else {
        int width = display.getWidth();
        int height = display.getHeight();
        size = new Point(width, height);
    }

    return size;
}

và sử dụng phương pháp này để tải hình ảnh của Picasso:

    final Point displySize = getDisplaySize(getWindowManager().getDefaultDisplay());
        final int size = (int) Math.ceil(Math.sqrt(displySize.x * displySize.y));
        Picasso.with(this)
                .load(urlSource)
                .resize(size, size)
                .centerInside()
                .into(imageViewd);

Ngoài ra, để có hiệu suất tốt hơn, bạn có thể tải xuống hình ảnh theo chiều rộng và chiều cao của màn hình hiển thị, không phải toàn bộ hình ảnh:

    public String reviseImageUrl(final Integer displayWidth,     final Integer displayHeight,
        final String originalImageUrl) {
    final String revisedImageUrl;

    if (displayWidth == null && displayHeight == null) {
        revisedImageUrl = originalImageUrl;
    } else {
        final Uri.Builder uriBuilder = Uri.parse(originalImageUrl).buildUpon();

        if (displayWidth != null && displayWidth > 0) {
            uriBuilder.appendQueryParameter(QUERY_KEY_DISPLAY_WIDTH, String.valueOf(displayWidth));
        }

        if (displayHeight != null && displayHeight > 0) {
            uriBuilder.appendQueryParameter(QUERY_KEY_DISPLAY_HEIGHT, String.valueOf(displayHeight));
        }

        revisedImageUrl = uriBuilder.toString();
    }

    return revisedImageUrl;
}

    final String newImageUlr = reviseImageUrl(displySize.x, displySize.y, urlSource);

và sau đó:

    Picasso.with(this)
                .load(newImageUlr)
                .resize(size, size)
                .centerInside()
                .into(imageViewd);

EDIT: getDisplaySize ()

display.getWidth()/getHeight()bị phản đối Thay vì Displaysử dụng DisplayMetrics.

public Point getDisplaySize(DisplayMetrics displayMetrics) {
        int width = displayMetrics.widthPixels;
        int height = displayMetrics.heightPixels;
        return new Point(width, height);
}

6

BitmapRegionDecoder không lừa

Bạn có thể ghi đè onDraw(Canvas canvas), bắt đầu một Chủ đề mới và giải mã khu vực hiển thị cho người dùng.


5

Như được chỉ ra bởi Larcho, bắt đầu từ API cấp 10, bạn có thể sử dụng BitmapRegionDecoderđể tải các vùng cụ thể từ một hình ảnh và với điều đó, bạn có thể thực hiện để hiển thị một hình ảnh lớn ở độ phân giải cao bằng cách phân bổ trong bộ nhớ chỉ các vùng cần thiết. Gần đây tôi đã phát triển một lib cung cấp khả năng hiển thị hình ảnh lớn với xử lý cử chỉ chạm. Mã nguồn và mẫu có sẵn ở đây .


3

Xem cấp độ

Bạn có thể tắt tăng tốc phần cứng cho chế độ xem riêng lẻ trong thời gian chạy với mã sau:

myView.setLayerType (View.LAYER_TYPE_SOFTware, null);


3

Tôi đã chạy qua cùng một vấn đề, đây là giải pháp của tôi. Đặt chiều rộng của hình ảnh giống như chiều rộng màn hình Android và sau đó chia tỷ lệ chiều cao

Bitmap myBitmap = BitmapFactory.decodeFile(image.getAbsolutePath());
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size.x;
int height = size.y;
Log.e("Screen width ", " "+width);
Log.e("Screen height ", " "+height);
Log.e("img width ", " "+myBitmap.getWidth());
Log.e("img height ", " "+myBitmap.getHeight());
float scaleHt =(float) width/myBitmap.getWidth();
Log.e("Scaled percent ", " "+scaleHt);
Bitmap scaled = Bitmap.createScaledBitmap(myBitmap, width, (int)(myBitmap.getWidth()*scaleHt), true);
myImage.setImageBitmap(scaled);

Điều này là tốt hơn cho bất kỳ kích thước màn hình Android. Hãy cho tôi biết nếu nó làm việc cho bạn.


2

Thu nhỏ hình ảnh:

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;

// Set height and width in options, does not return an image and no resource taken
BitmapFactory.decodeStream(imagefile, null, options);

int pow = 0;
while (options.outHeight >> pow > reqHeight || options.outWidth >> pow > reqWidth)
    pow += 1;
options.inSampleSize = 1 << pow; 
options.inJustDecodeBounds = false;
image = BitmapFactory.decodeStream(imagefile, null, options);

Hình ảnh sẽ được thu nhỏ lại ở kích thước của reqHeight và reqWidth. Theo tôi hiểu, inSampleSize chỉ nhận được 2 giá trị.


Làm thế nào để biết reqHeight và reqWidth? Ý tôi là chúng ta cần sửa nó thành giá trị tĩnh? hoặc chúng ta có thể thay đổi những thiết bị wrt?
Prashanth Debbadwar

2

Sử dụng thư viện Glide thay vì tải trực tiếp vào hình ảnh

Lướt: https://github.com/bumptech/glide

Glide.with(this).load(Uri.parse(filelocation))).into(img_selectPassportPic);

2
Sử dụng Glide thay vì Picasso đã giúp. Có vẻ như Glide xử lý các vấn đề như vậy theo mặc định
Johnny Five

1

Tôi đã thử tất cả các giải pháp ở trên, hết lần này đến lần khác, trong nhiều giờ, và dường như không có giải pháp nào hiệu quả! Cuối cùng, tôi quyết định xem xét một ví dụ chính thức liên quan đến việc chụp ảnh bằng camera của Android và hiển thị chúng. Ví dụ chính thức ( ở đây ), cuối cùng đã cho tôi phương pháp duy nhất có hiệu quả. Dưới đây tôi trình bày giải pháp tôi tìm thấy trong ứng dụng ví dụ đó:

public void setThumbnailImageAndSave(final ImageView imgView, File imgFile) {

            /* There isn't enough memory to open up more than a couple camera photos */
    /* So pre-scale the target bitmap into which the file is decoded */

    /* Get the size of the ImageView */
    int targetW = imgView.getWidth();
    int targetH = imgView.getHeight();

    /* Get the size of the image */
    BitmapFactory.Options bmOptions = new BitmapFactory.Options();
    bmOptions.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(imgFile.getAbsolutePath(), bmOptions);
    int photoW = bmOptions.outWidth;
    int photoH = bmOptions.outHeight;

    /* Figure out which way needs to be reduced less */
    int scaleFactor = 1;
    if ((targetW > 0) || (targetH > 0)) {
        scaleFactor = Math.min(photoW/targetW, photoH/targetH);
    }

    /* Set bitmap options to scale the image decode target */
    bmOptions.inJustDecodeBounds = false;
    bmOptions.inSampleSize = scaleFactor;
    bmOptions.inPurgeable = true;

    /* Decode the JPEG file into a Bitmap */
    Bitmap bitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath(), bmOptions);

    /* Associate the Bitmap to the ImageView */
    imgView.setImageBitmap(bitmap);
    imgView.setVisibility(View.VISIBLE);
}

0

LƯU Ý CHO NHỮNG AI MUỐN ĐƯA RA HÌNH ẢNH KÍCH THƯỚC NHỎ:

Giải pháp của Pilot_51 (di chuyển hình ảnh của bạn vào drawable-nodpithư mục) hoạt động, nhưng có một vấn đề khác: Nó làm cho hình ảnh QUÁ NHỎ trên màn hình trừ khi hình ảnh được thay đổi kích thước thành độ phân giải rất lớn (như 2000 x 3800) để phù hợp với màn hình - sau đó nó làm cho ứng dụng của bạn nặng hơn .

GIẢI PHÁP : đặt các tập tin hình ảnh của bạn vào drawable-hdpi- Nó hoạt động như một cơ duyên đối với tôi.


1
Bạn chỉ đang che giấu vấn đề mật độ hình ảnh của bạn. Trên phần cứng với mật độ thấp, hình ảnh của bạn sẽ trông lớn hơn.
rupps

Tôi cũng không nghĩ rằng giải pháp của Pilot_51 có bất kỳ vấn đề nào, bạn nên sử dụng kích thước hình ảnh phù hợp theo nhu cầu của mình
Nilabja

0

Sử dụng thư mục con có thể vẽ chính xác đã giải quyết nó cho tôi. Giải pháp của tôi là đưa hình ảnh độ phân giải đầy đủ của tôi (1920x1200) vào thư mục drawable-xhdpi , thay vì thư mục drawable .

Tôi cũng đặt một hình ảnh thu nhỏ (1280x800) vào thư mục drawable-hdpi .

Hai độ phân giải này phù hợp với máy tính bảng Nexus 7 2013 và 2012 tôi đang lập trình. Tôi cũng đã thử nghiệm giải pháp trên một số máy tính bảng khác.


0
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {

    super.onActivityResult(requestCode, resultCode, data);
    ///*
    if (requestCode == PICK_FROM_FILE && resultCode == RESULT_OK && null != data){



        uri = data.getData();

        String[] prjection ={MediaStore.Images.Media.DATA};

        Cursor cursor = getContentResolver().query(uri,prjection,null,null,null);

        cursor.moveToFirst();

        int columnIndex = cursor.getColumnIndex(prjection[0]);

        ImagePath = cursor.getString(columnIndex);

        cursor.close();

        FixBitmap = BitmapFactory.decodeFile(ImagePath);

        ShowSelectedImage = (ImageView)findViewById(R.id.imageView);

      //  FixBitmap = new BitmapDrawable(ImagePath);
        int nh = (int) ( FixBitmap.getHeight() * (512.0 / FixBitmap.getWidth()) );
        FixBitmap = Bitmap.createScaledBitmap(FixBitmap, 512, nh, true);

       // ShowSelectedImage.setImageBitmap(BitmapFactory.decodeFile(ImagePath));

        ShowSelectedImage.setImageBitmap(FixBitmap);

    }
}

Mã này là công việc

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.