I'd like to be able to resize an image by keeping a ratio aspect. Right now it is "complex" to do with a new Target and we are losing some great "build in" feature of Picasso.
One example would be for a resize on width:
Picasso.with(context).load(url).resize(400, -1).into(imageView);
Thanks
You could use a custom transformation to achieve the effect
private Transformation cropPosterTransformation = new Transformation() {
@Override public Bitmap transform(Bitmap source) {
int targetWidth = ...;
double aspectRatio = (double) source.getHeight() / (double) source.getWidth();
int targetHeight = (int) (targetWidth * aspectRatio);
Bitmap result = Bitmap.createScaledBitmap(source, targetWidth, targetHeight, false);
if (result != source) {
// Same bitmap is returned if sizes are the same
source.recycle();
}
return result;
}
@Override public String key() {
return "cropPosterTransformation" + desiredWidth;
}
};
Thanks for the reply. We can also do it with a transform but it remains "complex" and requires to write "code".
My request is to make this simple which is the philosophy of this framework.
Thanks for feedback, we will consider adding an API for this. In the meantime what @f2prateek posted above should do.
This is exactly what centerInside()
does.
Unless you're trying to resize an allow the bitmap to dictate the size in your layouts. Strange, but I've seen stranger.
Picasso.with(getActivity()).load(story.image_url).into(new Target() {
@Override
public void onBitmapLoaded(Bitmap bitmap, LoadedFrom loadedFrom) {
//whatever algorithm here to compute size
float ratio = (float) bitmap.getHeight() / (float) bitmap.getWidth();
float heightFloat = ((float) targetWidth) * ratio;
final android.view.ViewGroup.MarginLayoutParams layoutParams = (MarginLayoutParams) imageView.getLayoutParams();
layoutParams.height = (int) heightFloat;
layoutParams.width = (int) targetWidth;
imageView.setLayoutParams(layoutParams);
imageView.setImageBitmap(bitmap);
}
@Override
public void onBitmapFailed() {}
});
As a sidenote, do not use anonymous Target
classes as they might get gc'ed by the time download/decode has completed.
Thanks for this reply @dnkoutso.
Thumbor does this by allowing zero as the dimension you wish to scale with regard to aspect ratio. I'm inclined to follow suit.
I have been using the solution that @f2prateek proposed (I want to scale down the huge camera images to a maximum of 800 pixels on the _longest_ dimention), but unfortunately Crashlytics is telling me that some people are having OutOfMemory errors when Picasso does this.
@Override
public Bitmap transform(Bitmap source)
{
boolean isLandscape = source.getWidth() > source.getHeight();
int newWidth, newHeight;
if (isLandscape)
{
newWidth = MAX_DIMENSION_FOR_UPLOAD;
newHeight = Math.round(((float) newWidth / source.getWidth()) * source.getHeight());
} else
{
newHeight = MAX_DIMENSION_FOR_UPLOAD;
newWidth = Math.round(((float) newHeight / source.getHeight()) * source.getWidth());
}
Bitmap result = Bitmap.createScaledBitmap(source, newWidth, newHeight, false);
if (result != source)
source.recycle();
return result;
}
Some high end devices take massive pictures (8MP cameras these days..), so I'm wondering if this proposed resize() change will alleviate this...
My above transformation sometimes crashes on high end devices with the following:
Fatal Exception: java.lang.OutOfMemoryError
android.graphics.Bitmap.nativeCreate (Bitmap.java)
android.graphics.Bitmap.createBitmap (Bitmap.java:812)
com.squareup.picasso.BitmapHunter.transformResult (BitmapHunter.java:455)
com.squareup.picasso.BitmapHunter.hunt (BitmapHunter.java:154)
com.squareup.picasso.RequestCreator.get (RequestCreator.java:279)
I too would love to not have to worry about writing my own custom transformation to perform what is effectively a resize(). :)
800 pixels on the longest dimention
Use .resize(800, 800).centerInside()
for now.
Oh whoa, that works? I always figured that would distort the aspect ratio.
Does this solution work with .get()? I'm using .get() because I'm uploading the images - not placing them in an ImageView.
Both .centerInside()
and .centerCrop()
preserve aspect ratio during a resize.
And yes, it works with .get()
.
Thanks for the tip! I might point out that the Javadoc for centerInside doesn't explicitly mention that it preserves the aspect ratio, while the Javadoc for centerCrop _does_, hence my confusion.
Final question - is it more efficient (memory-wise) to use .resize(MAX_SIZE_LENGTH, MAX_SIZE_LENGTH).centerInside()
compared to a transformation which achieves the same goal, such as the one I posted above?
is it more efficient (memory-wise) to use
resize().centerInside()
compared to a transformation.
Sometimes depending on the source image. If the image is massive, Picasso will downsample it while decoding since it knows the destination size. For example, in your 8MP image world Picasso decodes the full image before handing it to the transformation whereas when using resize we downsample the image to be smaller while decoding to be much smaller and then do a tiny resize to the final size.
Makes perfect sense. This is actually what I was doing myself (downsample during load, then resize after) before I decided to stop re-inventing the wheel and start using Picasso. Thanks for your help! You are a gentleman and a scholar.
@nicolaslauquin Your way is perfect but the code in ( onBitmapLoaded() method ) didn't call at all , why ??????
@MinaMohsen This might not be the place for asking such support in this thread. I have no idea about your problem but I would check what happen on the onBitmapFailed callback.
Closing.
I'm just confirming that this worked for me. I have the imageView xml set to centerInside then i just specify a width, in my case it is the width of the screen, and then it maintains the aspect ratio. I just pass in 0 for the height.
Picasso.with(context).load(url).resize(width, 0).into(imageView);
Most helpful comment
I'm just confirming that this worked for me. I have the imageView xml set to centerInside then i just specify a width, in my case it is the width of the screen, and then it maintains the aspect ratio. I just pass in 0 for the height.
Picasso.with(context).load(url).resize(width, 0).into(imageView);