I am using the zing library for generating the QR code and I have generated the simple QR Code using URL,Text etc. but my question is that how can i generate the QR Code with company logo in middle of Qr Code.
I have found so many answer in stack overflow but non of them can solve my problem.
I already generated for my project (Kotlin answer)
fun CreateQRCode(qrCodeData: String) {
try {
val hintMap = HashMap<EncodeHintType, ErrorCorrectionLevel>()
val width = 250
val height = 250
val smallestDimension = if (width < height) width else height
hintMap[EncodeHintType.ERROR_CORRECTION] = ErrorCorrectionLevel.H
val qrCodeWriter = QRCodeWriter()
val bitMatrix = qrCodeWriter.encode(
qrCodeData,
BarcodeFormat.QR_CODE,
smallestDimension, smallestDimension) // width x height
val pixels = IntArray(smallestDimension * smallestDimension)
// All are 0, or black, by default
for (y in 0 until height) {
val offset = y * smallestDimension
for (x in 0 until smallestDimension) {
//pixels[offset + x] = matrix.get(x, y) ? BLACK : WHITE;
pixels[offset + x] = if (bitMatrix.get(x, y))
ResourcesCompat.getColor(resources, R.color.colorPrimary, null)
else
Color.WHITE
}
}
// var image = DataMatrixWriter.toBufferedImage(bitMatrix)
// Load logo image
// var overly = getOverly(LOGO);
val bitmap = Bitmap.createBitmap(smallestDimension, smallestDimension, Bitmap.Config.ARGB_8888)
bitmap.setPixels(pixels, 0, smallestDimension, 0, 0, smallestDimension, smallestDimension)
//setting bitmap to image view
val options = BitmapFactory.Options()
options.outWidth = 250
options.inJustDecodeBounds = false
options.outHeight = 250
var overlay = BitmapFactory.decodeResource(getResources(), R.mipmap.sugary_qr_icon, options);
overlay = Bitmap.createScaledBitmap(overlay, 50, 50, true)
val merged = mergeBitmaps(overlay, bitmap)
var _params = RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT)
_params.addRule(Gravity.CENTER_VERTICAL)
// ivQrCode!!.setPadding(180, 180, 180, 180)
ivQrCode!!.layoutParams = _params;
ivQrCode!!.setImageBitmap(merged)
// return bitmap;
} catch (er: Exception) {
if (debug)
er.printStackTrace()
}
}
mergeBitmaps function
private fun mergeBitmaps(overlay: Bitmap, bitmap: Bitmap): Bitmap {
val height = bitmap.height
val width = bitmap.width
val combined = Bitmap.createBitmap(width, height, bitmap.config)
val canvas = Canvas(combined)
val canvasWidth = canvas.width
val canvasHeight = canvas.height
canvas.drawBitmap(bitmap, Matrix(), null)
Log.e("WIDTH", canvasWidth.toString() + " " + overlay.width)
val centreX = (canvasWidth - overlay.width) / 2
val centreY = (canvasHeight - overlay.height) / 2
canvas.drawBitmap(overlay, centreX.toFloat(), centreY.toFloat(), null)
val bmOverlay = Bitmap.createBitmap(overlay.width, overlay.height, overlay.config);
var canvas = Canvas(bmOverlay);
canvas.drawBitmap(overlay, Matrix(), null);
canvas.drawBitmap(bitmap, 0f, 0f, null);
return bmOverlay
}
Related
I have getting one problem, when i am convert view to bitmap then resize bitmap it's getting low quality of image using scale.
My code is here,
`fun scaleBitmap(bitmap: Bitmap, wantedWidth: Int, wantedHeight: Int): Bitmap? {
val originalWidth = bitmap.width.toFloat()
val originalHeight = bitmap.height.toFloat()
val output =Bitmap.createBitmap(wantedWidth,wantedHeight,Bitmap.Config.ARGB_8888)
val canvas = Canvas(output)
val m = Matrix()
val scalex = wantedWidth / originalWidth
val scaley = wantedHeight / originalHeight
val xTranslation = 0.2f
val yTranslation = (wantedHeight - originalHeight * scaley) / 1.0f
m.postScale(scalex, scaley)
m.postTranslate(xTranslation, yTranslation)
canvas.drawBitmap(bitmap, m, Paint(Paint.FILTER_BITMAP_FLAG))
return output
}`
With androidx.compose.foundation.Canvas, default Canvas for Jetpack Compose, or Spacer with Modifier.drawBehind{} under the hood
#Composable
fun Canvas(modifier: Modifier, onDraw: DrawScope.() -> Unit) =
Spacer(modifier.drawBehind(onDraw
correctly refreshes drawing on Canvas when mutableState Offset changes
var offset by remember {
mutableStateOf(Offset(bitmapWidth / 2f, bitmapHeight / 2f))
}
Canvas(modifier = canvasModifier.fillMaxSize()) {
val canvasWidth = size.width.roundToInt()
val canvasHeight = size.height.roundToInt()
drawImage(
image = dstBitmap,
srcSize = IntSize(dstBitmap.width, dstBitmap.height),
dstSize = IntSize(canvasWidth, canvasHeight)
)
drawCircle(
center = offset,
color = Color.Red,
radius = canvasHeight.coerceAtMost(canvasWidth) / 8f,
)
}
With androidx.compose.ui.graphics.Canvas, Canvas that takes an ImageBitmap as argument and draws to as in description of it
Create a new Canvas instance that targets its drawing commands to the
provided ImageBitmap
I add full implementation to test this out easily and much appreciated if you come up with a solution.
#Composable
fun NativeCanvasSample2(imageBitmap: ImageBitmap, modifier: Modifier) {
BoxWithConstraints(modifier) {
val imageWidth = constraints.maxWidth
val imageHeight = constraints.maxHeight
val bitmapWidth = imageBitmap.width
val bitmapHeight = imageBitmap.height
var offset by remember {
mutableStateOf(Offset(bitmapWidth / 2f, bitmapHeight / 2f))
}
val canvasModifier = Modifier.pointerMotionEvents(
Unit,
onDown = {
val position = it.position
val offsetX = position.x * bitmapWidth / imageWidth
val offsetY = position.y * bitmapHeight / imageHeight
offset = Offset(offsetX, offsetY)
it.consumeDownChange()
},
onMove = {
val position = it.position
val offsetX = position.x * bitmapWidth / imageWidth
val offsetY = position.y * bitmapHeight / imageHeight
offset = Offset(offsetX, offsetY)
it.consumePositionChange()
},
delayAfterDownInMillis = 20
)
val canvas: androidx.compose.ui.graphics.Canvas = Canvas(imageBitmap)
val paint1 = remember {
Paint().apply {
color = Color.Red
}
}
canvas.apply {
val nativeCanvas = this.nativeCanvas
val canvasWidth = nativeCanvas.width.toFloat()
val canvasHeight = nativeCanvas.height.toFloat()
drawCircle(
center = offset,
radius = canvasHeight.coerceAtMost(canvasWidth) / 8,
paint = paint1
)
}
Image(
modifier = canvasModifier,
bitmap = imageBitmap,
contentDescription = null,
contentScale = ContentScale.FillBounds
)
Text(
"Offset: $offset",
modifier = Modifier.align(Alignment.BottomEnd),
color = Color.White,
fontSize = 16.sp
)
}
}
First issue it never refreshes Canvas without Text or something else reading Offset.
Second issue is as in the image below. It doesn't clear previous drawing on Image, i tried every possible solution in this question thread but none of them worked.
I tried drawing image with BlendMode, drawColor(Color.TRANSPARENT,Mode.Multiply) with native canvas and many combinations still not able to have the same result with Jetpack Compose Canvas.
val erasePaint = remember {
Paint().apply {
color = Color.Transparent
blendMode = BlendMode.Clear
}
}
with(canvas.nativeCanvas) {
val checkPoint = saveLayer(null, null)
drawImage(imageBitmap, topLeftOffset = Offset.Zero, erasePaint)
drawCircle(
center = offset,
radius = canvasHeight.coerceAtMost(canvasWidth) / 8,
paint = paint1
)
restoreToCount(checkPoint)
}
I need to use androidx.compose.ui.graphics.Canvas as you can see operations on Canvas are reflected to Bitmap and using this i'm planning to create foundation for cropping Bitmap
I finally, after 6 months, figured out how it can be done and how you can modify Bitmap instance using androidx.compose.ui.graphics.Canvas
First create an empty mutable bitmap with same dimensions of original bitmap. This is what we will draw on. The trick here is not sending a real bitmap but an empty bitmap
val bitmapWidth = imageBitmap.width
val bitmapHeight = imageBitmap.height
val bmp: Bitmap = remember {
Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888)
}
Then since we draw nothing at the base we can use drawColor(android.graphics.Color.TRANSPARENT, PorterDuff.Mode.CLEAR)
to clear on each draw then draw image and apply any blend mode using Paint
val paint = remember {
Paint()
}
val erasePaint = remember {
Paint().apply {
color = Color.Red
blendMode = BlendMode.SrcIn
}
}
canvas.apply {
val nativeCanvas = this.nativeCanvas
val canvasWidth = nativeCanvas.width.toFloat()
val canvasHeight = nativeCanvas.height.toFloat()
with(canvas.nativeCanvas) {
drawColor(android.graphics.Color.TRANSPARENT, PorterDuff.Mode.CLEAR)
drawCircle(
center = offset,
radius = 400f,
paint = paint
)
drawImageRect(
image = imageBitmap,
dstSize = IntSize(canvasWidth.toInt(), canvasHeight.toInt()),
paint = erasePaint
)
}
}
Finally draw bitmap we used in Canvas to Image Composable using
Image(
modifier = canvasModifier.border(2.dp, Color.Green),
bitmap = bmp.asImageBitmap(),
contentDescription = null,
contentScale = ContentScale.FillBounds
)
or you can save this modified ImageBitmap with watermark or any overlay you draw into canvas
Full implementation
#Composable
fun NativeCanvasSample2(imageBitmap: ImageBitmap, modifier: Modifier) {
BoxWithConstraints(modifier) {
val imageWidth = constraints.maxWidth
val imageHeight = constraints.maxHeight
val bitmapWidth = imageBitmap.width
val bitmapHeight = imageBitmap.height
var offset by remember {
mutableStateOf(Offset(bitmapWidth / 2f, bitmapHeight / 2f))
}
val bmp: Bitmap = remember {
Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888)
}
val canvas: Canvas = remember {
Canvas(bmp.asImageBitmap())
}
val paint = remember {
Paint()
}
val erasePaint = remember {
Paint().apply {
color = Color.Red
blendMode = BlendMode.SrcIn
}
}
canvas.apply {
val nativeCanvas = this.nativeCanvas
val canvasWidth = nativeCanvas.width.toFloat()
val canvasHeight = nativeCanvas.height.toFloat()
with(canvas.nativeCanvas) {
drawColor(android.graphics.Color.TRANSPARENT, PorterDuff.Mode.CLEAR)
drawCircle(
center = offset,
radius = 400f,
paint = paint
)
drawImageRect(
image = imageBitmap,
dstSize = IntSize(canvasWidth.toInt(), canvasHeight.toInt()),
paint = erasePaint
)
}
}
val canvasModifier = Modifier.pointerMotionEvents(
Unit,
onDown = {
val position = it.position
val offsetX = position.x * bitmapWidth / imageWidth
val offsetY = position.y * bitmapHeight / imageHeight
offset = Offset(offsetX, offsetY)
it.consume()
},
onMove = {
val position = it.position
val offsetX = position.x * bitmapWidth / imageWidth
val offsetY = position.y * bitmapHeight / imageHeight
offset = Offset(offsetX, offsetY)
it.consume()
},
delayAfterDownInMillis = 20
)
Image(
modifier = canvasModifier.border(2.dp, Color.Green),
bitmap = bmp.asImageBitmap(),
contentDescription = null,
contentScale = ContentScale.FillBounds
)
}
}
Result
I am trying to make an extension function to use it in a different class. I am trying to create it but it does not work. Can anyone solve this problem.
Here is my extension:
fun resize.toBitmap(image: Bitmap, maxWidth: Int, maxHeight: Int): Bitmap {
var image = image
return if (maxHeight > 0 && maxWidth > 0) {
val width = image.width
val height = image.height
val ratioBitmap = width.toFloat() / height.toFloat()
val ratioMax = maxWidth.toFloat() / maxHeight.toFloat()
var finalWidth = maxWidth
var finalHeight = maxHeight
if (ratioMax > ratioBitmap) {
finalWidth = (maxHeight.toFloat() * ratioBitmap).toInt()
} else {
finalHeight = (maxWidth.toFloat() / ratioBitmap).toInt()
}
image = Bitmap.createScaledBitmap(image, finalWidth, finalHeight, true)
image
} else {
image
}
And this is how I try to reach it:
var bitmap = Bitmap.createBitmap(drawingCacheBitmap)
bitmap = resize(bitmap, 200, 100)
Try this
fun Bitmap.resizeImage(image: Bitmap, maxWidth: Int, maxHeight: Int): Bitmap {
val width = image.width
val height = image.height
val scaleWidth = maxWidth.toFloat() / width
val scaleHeight = maxHeight.toFloat() / height
val matrix = Matrix()
matrix.postScale(scaleWidth, scaleHeight)
// Create a New bitmap
val resizedBitmap = Bitmap.createBitmap(
image, 0, 0, width, height, matrix, false)
resizedBitmap.recycle()
return resizedBitmap
}
And call this extension function like this,
bitmap = resizeImage(bitmap, 200, 100)
How i can set bitmap image in center it is not in center .Here is my code and screen.I tried so much but I failed to solves this
fun onDraw(c: Canvas, rectF: RectF, pos: Int) {
val p = Paint()
p.color = color
c.drawRect(rectF, p)
p.color = Color.WHITE
p.textSize - textSize.toFloat()
var r = Rect()
val cHeight = rectF.height()
val cWidth = rectF.width()
p.textAlign = Paint.Align.RIGHT
p.getTextBounds(text, 0, text.length, r)
var x = 0f
var y = 0f
if (imageResId == 0) {
x = cWidth / 2f - r.width() / 2f - r.left.toFloat()
y = cHeight / 2f + r.height() / 2f - r.bottom.toFloat()
c.drawText(text, rectF.left + x, rectF.top + y, p)
} else {
val d = ContextCompat.getDrawable(context, imageResId)
val bitmap = drawableToBitmap(d!!)
c.drawBitmap(
bitmap,
(rectF.left + rectF.right) / 2,
(rectF.top + rectF.bottom) / 2,
p
)
}
clickRegion = rectF
this.pos = pos
}
Here is image link that is produce error
enter link description here
private fun drawableToBitmap(d: Drawable?): Bitmap {
if (d is BitmapDrawable) return d.bitmap
val bitmap =
Bitmap.createBitmap(d!!.intrinsicWidth, d.intrinsicHeight, Bitmap.Config.ARGB_8888)
var canvas = Canvas(bitmap)
d.setBounds(0, 0, canvas.width, canvas.height)
d.draw(canvas)
return bitmap
}
You can see that your drawables are all in center and draw from there, all you do are right, you just only need a simply offset with:
Subtract the half of the drawable's width & height from the start position
Red to Green
Code Snippet
c.drawBitmap(
bitmap,
(rectF.left + rectF.right) / 2,
(rectF.top + rectF.bottom) / 2,
p
)
To
c.drawBitmap(
bitmap,
(rectF.left + rectF.right - bitmap.width) / 2,
(rectF.top + rectF.bottom - bitmap.height) / 2,
p
)
What i have:: I have a Imageview for which i am making image as a circle using picassso
What i what to do:: I want to add a black border for rounded image using my current implementation, how to achieve this without using third party library
Picasso.with(this)
.load("http://i.imgur.com/DvpvklR.png")
.transform(new RoundedTransformation(50, 4))
.resize(100, 100)
.centerCrop().into(imageView1);
RoundedTransformation.java
// enables hardware accelerated rounded corners
// original idea here : http://www.curious-creature.org/2012/12/11/android-recipe-1-image-with-rounded-corners/
public class RoundedTransformation implements com.squareup.picasso.Transformation {
private final int radius;
private final int margin; // dp
// radius is corner radii in dp
// margin is the board in dp
public RoundedTransformation(final int radius, final int margin) {
this.radius = radius;
this.margin = margin;
}
#Override
public Bitmap transform(final Bitmap source) {
final Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setShader(new BitmapShader(source, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
Bitmap output = Bitmap.createBitmap(source.getWidth(), source.getHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(output);
canvas.drawRoundRect(new RectF(margin, margin, source.getWidth() - margin, source.getHeight() - margin), radius, radius, paint);
if (source != output) {
source.recycle();
}
return output;
}
#Override
public String key() {
return "rounded";
}
}
EDIT
public class RoundedTransformation implements com.squareup.picasso.Transformation {
private final int radius;
private final int margin; // dp
// radius is corner radii in dp
// margin is the board in dp
public RoundedTransformation(final int radius, final int margin) {
this.radius = radius;
this.margin = margin;
}
#Override
public Bitmap transform(final Bitmap source) {
final Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setShader(new BitmapShader(source, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
Bitmap output = Bitmap.createBitmap(source.getWidth(), source.getHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(output);
canvas.drawRoundRect(new RectF(margin, margin, source.getWidth() - margin, source.getHeight() - margin), radius, radius, paint);
if (source != output) {
source.recycle();
}
Paint paint1 = new Paint();
paint1.setColor(Color.RED);
paint1.setStyle(Style.STROKE);
paint1.setAntiAlias(true);
paint1.setStrokeWidth(2);
canvas.drawCircle((source.getWidth() - margin)/2, (source.getHeight() - margin)/2, radius-2, paint1);
return output;
}
#Override
public String key() {
return "rounded";
}
}
Final transformation class, thanks to blackbelt
public class RoundedTransformation implements com.squareup.picasso.Transformation {
private final int radius;
private final int margin; // dp
// radius is corner radii in dp
// margin is the board in dp
public RoundedTransformation(final int radius, final int margin) {
this.radius = radius;
this.margin = margin;
}
#Override
public Bitmap transform(final Bitmap source) {
final Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setShader(new BitmapShader(source, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
Bitmap output = Bitmap.createBitmap(source.getWidth(), source.getHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(output);
canvas.drawCircle((source.getWidth() - margin)/2, (source.getHeight() - margin)/2, radius-2, paint);
if (source != output) {
source.recycle();
}
Paint paint1 = new Paint();
paint1.setColor(Color.RED);
paint1.setStyle(Style.STROKE);
paint1.setAntiAlias(true);
paint1.setStrokeWidth(2);
canvas.drawCircle((source.getWidth() - margin)/2, (source.getHeight() - margin)/2, radius-2, paint1);
return output;
}
#Override
public String key() {
return "rounded";
}
}
you can use drawCircle with another Paint object. For instance:
Paint paint = new Paint();
paint.setColor(Color.RED);
paint.setStyle(Style.STROKE);
paint.setAntiAlias(true);
paint.setStrokeWidth(2);
canvas.drawCircle((source.getWidth() - margin)/2, (source.getHeight() - margin)/2, radius-2, paint);
Also, instead of using a drawRoundRect to draw a circle, you can use drawCircle
Answers of BlackBelt and Devrath are great. And if you are looking for a Kotlin version of this class, here it is:
class RoundedBorderTransform(private val radius: Int, private val margin: Int) : com.squareup.picasso.Transformation {
override fun transform(source: Bitmap?): Bitmap {
val paint = Paint()
paint.isAntiAlias = true
paint.shader = BitmapShader(source!!, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
val output = Bitmap.createBitmap(source.width, source.height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(output)
canvas.drawCircle((source.width - margin) / 2f, (source.height - margin) / 2f, radius - 2f, paint)
if (source != output) {
source.recycle()
}
val borderPaint = Paint()
borderPaint.color = Color.RED
borderPaint.style = Paint.Style.STROKE
borderPaint.isAntiAlias = true
borderPaint.strokeWidth = 2f
canvas.drawCircle((source.width - margin) / 2f, (source.height - margin) / 2f, radius - 2f, borderPaint)
return output
}
override fun key(): String {
return "roundedBorder"
}
}
This is solution for circle and rectangle shapes. Also it's useful not only for Picasso usage, but for general android Canvas-tasks.
I've created them very voluminous and detailed only for yours understanding of processes, shorten as you want.
But I want to clarify a main problem that many people faced with.
In android there no possibilities to create inner or outer border - only centered:
And this is the reason why you receive border elements cut off like these:
So there only a single way to recalculate position of border: in case of
circle you have to decrease circle radius by HALF OF BORDER WIDTH
rectangle you have to 1) shift border lines "inside" by HALF OF BORDER WIDTH; 2) decrease corner radius by HALF OF BORDER WIDTH
These actions will provide you an expected results:
If you're need only code for you border - pick only correspondent drawBorder() method.
Here is an example for empty Fragment with two images:
ViewsCroppingAndBorderingTestFragment.kt
class ViewsCroppingAndBorderingTestFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_test_views_cropping_and_bordering, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val urlCircle = "https://images-na.ssl-images-amazon.com/images/I/71zLQIfmTlL._AC_SX466_.jpg"
val urlRectRounded = "https://www.gardendesign.com/pictures/images/675x529Max/site_3/helianthus-yellow-flower-pixabay_11863.jpg"
val ivCircle = view.findViewById<ImageView>(R.id.ivCircle)
val ivRectRounded = view.findViewById<ImageView>(R.id.ivRectRounded)
val trCircle = CircleTransformation()
val trRectRounded = RectRoundedTransformation()
Picasso.get().load(urlCircle).transform(trCircle).into(ivCircle)
Picasso.get().load(urlRectRounded).transform(trRectRounded).into(ivRectRounded)
}
class CircleTransformation() : Transformation {
override fun transform(source: Bitmap): Bitmap {
val size = Math.min(source.width, source.height)
val x = (source.width - size) / 2
val y = (source.height - size) / 2
val w = size
val h = size
val squaredBitmap = Bitmap.createBitmap(source, x, y, w, h)
if (squaredBitmap != source) {
source.recycle()
}
val bitmap = Bitmap.createBitmap(w, h, source.config)
val canvas = Canvas(bitmap)
// >> Draw original rectangle image
// val paint = Paint(Paint.ANTI_ALIAS_FLAG)
// canvas.drawBitmap(squaredBitmap, 0F, 0F, paint)
val rImage = w / 2f
cropWithCircle(squaredBitmap, canvas, rImage)
squaredBitmap.recycle()
drawBorder(canvas, rImage)
return bitmap
}
private fun cropWithCircle(bitmapSource: Bitmap, canvas: Canvas, rImage: Float) {
val shader = BitmapShader(bitmapSource, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
val paint = Paint(Paint.ANTI_ALIAS_FLAG)
paint.shader = shader
paint.isAntiAlias = true
val xCenter = rImage
val yCenter = rImage
canvas.drawCircle(xCenter, yCenter, rImage, paint)
}
private fun drawBorder(canvas: Canvas, rImage: Float) {
val borderWidth = 30F
val paintBorder = Paint()
paintBorder.strokeWidth = borderWidth
paintBorder.style = Paint.Style.STROKE
paintBorder.color = Color.GREEN
paintBorder.isAntiAlias = true
val cCenter = rImage
val yCenter = rImage
// ANDROID'S BORDER IS ALWAYS CENTERED.
// So have to reduce radius by half of border's width
val rBorder = rImage - borderWidth / 2
canvas.drawCircle(cCenter, yCenter, rBorder, paintBorder)
}
override fun key(): String {
return "circle"
}
}
class RectRoundedTransformation() : Transformation {
override fun transform(source: Bitmap): Bitmap {
val x = 0
val y = 0
val w = source.width
val h = source.height
val squaredBitmap = Bitmap.createBitmap(source, x, y, w, h)
if (squaredBitmap != source) {
source.recycle()
}
val bitmap = Bitmap.createBitmap(w, h, source.config)
val canvas = Canvas(bitmap)
// >> Draw original rectangle image
// val paint = Paint(Paint.ANTI_ALIAS_FLAG)
// canvas.drawBitmap(squaredBitmap, 0F, 0F, paint)
val rCorner = 80F
cropCorners(squaredBitmap, canvas, rCorner)
squaredBitmap.recycle()
drawBorder(canvas, rCorner)
return bitmap
}
private fun cropCorners(bitmapSource: Bitmap, canvas: Canvas, rCorner: Float) {
val width = canvas.width
val height = canvas.height
val maskBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ALPHA_8)
val maskCanvas = Canvas(maskBitmap)
val maskPaint = Paint(Paint.ANTI_ALIAS_FLAG)
val maskRect = RectF(0F, 0F, width.toFloat(), height.toFloat())
// 1. draw base rect
maskCanvas.drawRect(maskRect, maskPaint)
// 2. cut off inner rounded rect, leave corners
maskPaint.xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR)
maskCanvas.drawRoundRect(maskRect, rCorner, rCorner, maskPaint)
// 3. draw original rectangle image
val paintSource = Paint(Paint.ANTI_ALIAS_FLAG)
canvas.drawBitmap(bitmapSource, 0f, 0f, paintSource)
// 4.cut off corners
val paintCropped = Paint(Paint.ANTI_ALIAS_FLAG or Paint.FILTER_BITMAP_FLAG)
paintCropped!!.xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR)
canvas.drawBitmap(maskBitmap!!, 0f, 0f, paintCropped)
}
private fun drawBorder(canvas: Canvas, rCorner: Float) {
val borderWidth = 30F
val paintBorder = Paint()
paintBorder.strokeWidth = borderWidth
paintBorder.style = Paint.Style.STROKE
paintBorder.color = Color.RED
paintBorder.isAntiAlias = true
// // ANDROID'S BORDER IS ALWAYS CENTERED.
// // So have to shift every side by half of border's width
val rectLeft = 0 + borderWidth / 2
val rectTop = 0 + borderWidth / 2
val rectRight = canvas.width.toFloat() - borderWidth / 2
val rectBottom = canvas.height.toFloat() - borderWidth / 2
val rectF = RectF(rectLeft, rectTop, rectRight, rectBottom)
// // So have to corner reduce radius by half of border's width
val rectRCorner = rCorner - borderWidth / 2
canvas.drawRoundRect(rectF, rectRCorner, rectRCorner, paintBorder)
}
override fun key(): String {
return "rectRounded"
}
}
}
fragment_test_views_cropping_and_bordering.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/temp"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="200dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:background="#android:color/darker_gray">
<ImageView
android:id="#+id/ivCircle"
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_margin="10dp"/>
<ImageView
android:id="#+id/ivRectRounded"
android:layout_width="200dp"
android:layout_height="160dp"
android:layout_margin="10dp"/>
</LinearLayout>