Skip to content

Instantly share code, notes, and snippets.

@smithaaron
Last active June 28, 2016 16:46
Show Gist options
  • Save smithaaron/5e8215920dc701c6402ce44b7fedcc14 to your computer and use it in GitHub Desktop.
Save smithaaron/5e8215920dc701c6402ce44b7fedcc14 to your computer and use it in GitHub Desktop.
This is a Picasso Transformation used to make images look like speech bubbles.
//In my case I first resize the image to a max width of 300dp as I'm displaying in a list and want them to look uniform
//Then for the margin and raidus measurements, I convert from dp to px, so that it appears the same on different screens.
Picasso.with(mContext)
.load(imageUrl)
.resize((int)UiUtils.dpToPx(mContext, 300), 0)
.transform(new SpeechBubbleTransform((int)UiUtils.dpToPx(mContext, 8), (int)UiUtils.dpToPx(mContext,12), SpeechBubbleTransform.Corner.BOTTOM_LEFT))
.into(holder.mIvPhotoMessage);
public static class SpeechBubbleTransform implements Transformation {
public enum Corner {
BOTTOM_LEFT,
BOTTOM_RIGHT
}
private final int mMargin;
private final int mCornerRadius;
private final Corner mCorner;
/**
* Transforms an image to look like a speech bubble, i.e. rounded corners and a tail on the bottom left or right.
* @param margin The size of the area around the image that will be cropped. This basically dictates how big the tail will be.
* @param cornerRadius Radius of rounded corners
* @param corner Which corner the tails will be placed on. BOTTOM_LEFT or BOTTOM_RIGHT
*/
public SpeechBubbleTransform(int margin, int cornerRadius, Corner corner) {
mMargin = margin;
mCornerRadius = cornerRadius;
mCorner = corner;
}
@Override
public Bitmap transform(Bitmap source) {
Bitmap output = Bitmap.createBitmap(source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(output);
int startX, startY, x1, y1, x2, y2, x3, y3, x4, y4;
// initialise coordinates based on what corner is set
switch (mCorner) {
case BOTTOM_LEFT:
startX = mMargin * 3;
startY = source.getHeight() - mMargin;
x1 = (int)(mMargin * 2.5);
y1 = source.getHeight();
x2 = 0;
y2 = source.getHeight();
x3 = mMargin;
y3 = source.getHeight() - mMargin;
x4 = mMargin;
y4 = source.getHeight() - mMargin * 3;
break;
case BOTTOM_RIGHT:
default:
startX = source.getWidth() - mMargin * 3;
startY = source.getHeight() - mMargin;
x1 = source.getWidth() - (int)(mMargin * 2.5);
y1 = source.getHeight();
x2 = source.getWidth();
y2 = source.getHeight();
x3 = source.getWidth() - mMargin;
y3 = source.getHeight() - mMargin;
x4 = source.getWidth()- mMargin;
y4 = source.getHeight() - mMargin * 3;
break;
}
Paint tailPaint = new Paint();
tailPaint.setAntiAlias(true);
tailPaint.setShader(new BitmapShader(source, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
Path tail = new Path();
tail.setFillType(Path.FillType.EVEN_ODD);
tail.moveTo(startX, startY);
tail.quadTo(x1 ,y1, x2, y2);
tail.quadTo(x3, y3, x4, y4);
tail.close();
final Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setShader(new BitmapShader(source, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
canvas.drawRoundRect(new RectF(mMargin, mMargin, source.getWidth() - mMargin, source.getHeight() - mMargin), mCornerRadius, mCornerRadius, paint);
canvas.drawPath(tail, tailPaint);
if (source != output) {
source.recycle();
}
return output;
}
@Override
public String key() {
return "bubble";
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment