juliano.net
juliano.net

Reputation: 8177

Set maximum width to load images with Picasso

I have a fixed header in my activity that I need to load images dynamically into it. I need this images to fill this header entirely, keep the width and height proportion.

If I load the image before, I get OutOfMemoryException. If I use Picasso's fit() method there will be blank spaces in the area. And if I use Transformation as some people in StackOverflow have suggested, I also get OutOfMemoryException.

How can I solve this?

Header XML:

<FrameLayout
        android:id="@+id/headerContainer"
        android:layout_width="match_parent"
        android:layout_height="140dp"
        android:layout_alignParentLeft="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentStart="true"
        android:layout_alignParentTop="true"
        android:background="#ffd5d5d5">


        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/imageView4"
            android:layout_gravity="center"
            android:src="@drawable/background_camera" />

        <ViewFlipper
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/viewFlipper"
            android:layout_gravity="center" >

        </ViewFlipper>


        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Adicionar foto do estacionamento"
            android:id="@+id/textAddPhotos"
            android:layout_gravity="center"
            android:textColor="#ff757575"
            android:padding="10dp" />

        <RelativeLayout
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:clickable="true"
            android:id="@+id/addPhotosArea"></RelativeLayout>

    </FrameLayout>

The images are added to the ViewFlipper programmatically using the following code:

final ImageView imageView = new ImageView(SuggestionActivity.this);
        imageView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));

        Picasso.with(SuggestionActivity.this).load(selectedImageUri)
                .fit().centerInside()
                .into(imageView);

        mViewFlipper.addView(imageView);

UPDATE

I figured out that Picasso is miscalculating the size when I load an image with exif orientation = 90º.

I'm trying to change its source, but the logic is pretty confusing.

I think the problem is in this function of the BitmapHunter.java file:

static Bitmap transformResult(Request data, Bitmap result, int exifRotation) {
    int inWidth = result.getWidth();
    int inHeight = result.getHeight();

    int drawX = 0;
    int drawY = 0;
    int drawWidth = inWidth;
    int drawHeight = inHeight;

    Matrix matrix = new Matrix();

    if (data.needsMatrixTransform()) {
      int targetWidth = data.targetWidth;
      int targetHeight = data.targetHeight;

      float targetRotation = data.rotationDegrees;
      if (targetRotation != 0) {
        if (data.hasRotationPivot) {
          matrix.setRotate(targetRotation, data.rotationPivotX, data.rotationPivotY);
        } else {
          matrix.setRotate(targetRotation);
        }
      }

      if (data.centerCrop) {
        float widthRatio = targetWidth / (float) inWidth;
        float heightRatio = targetHeight / (float) inHeight;
        float scale;
        if (widthRatio > heightRatio) {
          scale = widthRatio;
          int newSize = (int) Math.ceil(inHeight * (heightRatio / widthRatio));
          drawY = (inHeight - newSize) / 2;
          drawHeight = newSize;
        } else {
          scale = heightRatio;
          int newSize = (int) Math.ceil(inWidth * (widthRatio / heightRatio));
          drawX = (inWidth - newSize) / 2;
          drawWidth = newSize;
        }
        matrix.preScale(scale, scale);
      } else if (data.centerInside) {
        float widthRatio = targetWidth / (float) inWidth;
        float heightRatio = targetHeight / (float) inHeight;
        float scale = widthRatio < heightRatio ? widthRatio : heightRatio;
        matrix.preScale(scale, scale);
      } else if (targetWidth != 0 && targetHeight != 0 //
          && (targetWidth != inWidth || targetHeight != inHeight)) {
        // If an explicit target size has been specified and they do not match the results bounds,
        // pre-scale the existing matrix appropriately.
        float sx = targetWidth / (float) inWidth;
        float sy = targetHeight / (float) inHeight;
        matrix.preScale(sx, sy);
      }
    }

    if (exifRotation != 0) {
      matrix.preRotate(exifRotation);
    }

    Bitmap newResult =
        Bitmap.createBitmap(result, drawX, drawY, drawWidth, drawHeight, matrix, true);
    if (newResult != result) {
      result.recycle();
      result = newResult;
    }

    return result;
  }

Upvotes: 3

Views: 5329

Answers (2)

Jacob Tabak
Jacob Tabak

Reputation: 8094

Use .fit().centerCrop(), it should do what you're looking for.

Upvotes: 3

Denley Bihari
Denley Bihari

Reputation: 601

The ImageView must be added to the ViewFlipper before loading the image. This is so that Picasso knows the height/width of the ImageView, which it needs to scale the image properly to the size of the ImageView.

Change it to:

final ImageView imageView = new ImageView(SuggestionActivity.this);
imageView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));

mViewFlipper.addView(imageView);

Picasso.with(SuggestionActivity.this).load(selectedImageUri)
        .fit().centerInside()
        .into(imageView);

Upvotes: 2

Related Questions