How to draw dashed border with padding around bitmap android? - android

I would like to draw stroke around bitmap. getting left and right side point of bitmap and drawing line using path and points.
got border around bitmap using below code and set it below imageview. but when i apply padding it want draw border with appropriate padding.
private suspend fun drawBorder(
src: Bitmap,
colorToReplace: Int,
): Bitmap? {
return kotlin.runCatching {
withContext(IO) {
val width = src.width
val height = src.height
val pixels = IntArray(width * height)
// get pixel array from source
src.getPixels(pixels, 0, width, 0, 0, width , height )
val bmOut = Bitmap.createBitmap(width, height, src.config)
val canvas = Canvas(bmOut)
val paint = Paint().apply {
isAntiAlias = true
isDither = true
color = colorCode
style = Paint.Style.STROKE
strokeWidth = radius
strokeJoin = Paint.Join.ROUND
strokeCap = Paint.Cap.ROUND
}
if (isDashed) {
paint.pathEffect = DashPathEffect(floatArrayOf(50f, radius * 2), 0f)
}
var moved = false
val path = Path()
var pixel = 0
// iteration through pixels
for (y in height - 1 downTo 0) {
for (x in width - 1 downTo 0) {
val index = y * width + x
pixel = pixels[index]
if (pixel != colorToReplace) {
if (!moved) {
moved = true
path.moveTo(x.toFloat(), y.toFloat())
}
path.lineTo(if(isPadded) x.toFloat() + 20 else x.toFloat(), y.toFloat())
break
}
} //x
} //y
for (y in 0 until height) {
for (x in 0 until width) {
val index = y * width + x
pixel = pixels[index]
if (pixel != colorToReplace) {
path.lineTo(if(isPadded) x.toFloat() - 20 else x.toFloat(), if(isPadded) y.toFloat() - 20 else y.toFloat())
break
}
} //x
} //y
canvas.drawPath(path, paint)
bmOut
}
}.getOrNull()
}
Now i would like to draw dashed with padding like below image.
If anyone have idea please let me know. Thanks.

this is a function I used for the same, it could help you
private Bitmap addWhiteBorder(Bitmap bmp, int borderSize) {
Bitmap bmpWithBorder = Bitmap.createBitmap(bmp.getWidth() + borderSize * 2, bmp.getHeight() + borderSize * 2, bmp.getConfig());
Canvas canvas = new Canvas(bmpWithBorder);
canvas.drawColor(Color.WHITE);
canvas.drawBitmap(bmp, borderSize, borderSize, null);
return bmpWithBorder;
}
Basically, it creates a new Bitmap adding 2 * border size to each dimension, and then paints the original Bitmap over it, offsetting it with border size.
You make your bitmap bigger than the one you are adding to it and then fill the canvas with the background you want. If you need to add other effects you can look into the canvas options for clipping the rect and adding rounded corners and such.

Related

Draw outline from image

I wanted to draw a contour around the picture by drawing and expanding a second picture in the Background, but I wasn't very successful, how can I draw a regular stroke?
The contour I drew:
The contour I want to draw:
My Code;
private Bitmap ContourBitmap() {
int strokeWidth = 8;
Bitmap originalBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.flower_icon);
Bitmap newStrokedBitmap = Bitmap.createBitmap(originalBitmap.getWidth() + 2 * strokeWidth,
originalBitmap.getHeight() + 2 * strokeWidth, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(newStrokedBitmap);
float scaleX = (originalBitmap.getWidth() + 2.0f * strokeWidth) / originalBitmap.getWidth();
float scaleY = (originalBitmap.getHeight() + 2.0f * strokeWidth) / originalBitmap.getHeight();
Matrix matrix = new Matrix();
matrix.setScale(scaleX, scaleY);
canvas.drawBitmap(originalBitmap, matrix, null);
canvas.drawColor(Color.WHITE, PorterDuff.Mode.SRC_ATOP); //Color.WHITE is stroke color
canvas.drawBitmap(originalBitmap, strokeWidth, strokeWidth, null);
}
I think you are on the right track...
Here is a strategy, instead of scaling just draw the same original picture a few times each time slightly offset, see sample below:
var canvas = document.getElementById('canvas')
var ctx = canvas.getContext('2d')
var img = new Image;
img.onload = draw;
img.src = "http://i.stack.imgur.com/UFBxY.png";
var s = 10, // thickness scale
x = 15, // final position
y = 15;
function draw() {
ctx.globalAlpha = 0.2
ctx.filter = 'brightness(0%)'
for (i = 0; i < 360; i++)
ctx.drawImage(img, x + Math.sin(i) * s, y + Math.cos(i) * s);
ctx.globalAlpha = 1
ctx.filter = 'none'
ctx.drawImage(img, x, y);
}
<canvas id=canvas width=350 height=600></canvas>
I applied a filter = 'brightness(0%)' but there are many more you can apply:
https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/filter
I'm using HTML canvas but that same idea should "translate" nicely to an android canvas.

How to scale Canvas and draw thin border around the edge?

I have been struggling to get the preview of a PDF in the Android Print Framework to match the print output. However, I am able to get the output to match as a bitmap. However, if I scale the bitmap and put whitespace around the bitmap, the Print Framework crops out the whitespace. So, to prevent that from happening, I would like to draw a thin border around the edge of the entire Canvas.
This is the code that I have to scale the bitmap:
public static Bitmap captureScreen(View v) {
Bitmap screenshot = null;
Bitmap output = null;
try {
if (v != null) {
screenshot = Bitmap.createBitmap(v.getMeasuredWidth(), v.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
int width = screenshot.getWidth();
int height = screenshot.getHeight();
int scaledWidth = (int) (width * 0.5);
int scaledHeight = (int) (height * 0.5);
output = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Bitmap scaled = Bitmap.createScaledBitmap(screenshot, scaledWidth, scaledHeight, false);
Canvas canvas = new Canvas(output);
Paint paint = new Paint();
int distX = (width - scaledWidth) / 2;
int distY = (height - scaledHeight) / 2;
canvas.drawBitmap(scaled, distX, distY, paint);
v.draw(canvas);
}
} catch (Exception e) {
Log.d("ScreenShotActivity", "Failed to capture screenshot because:" + e.getMessage());
}
return output;
}
I would like to draw a thin black border around the entire canvas for I can prevent the whitespace from being cropped out by the Print Framework.
Well, you have the width and height of the canvas, just call Canvas.drawRect(0, 0, width - 1, height - 1, strokePaint)?

android draw stroke on multi line text

Hi i'am trying to add stroke on multi line text but its not working
this is the code
first draw the fill text its works fine
but when try to draw the stroke it's not work and give me something that not related to stroke
i need stroke like this but to multi line text
stroke canvas
textPaint.setStyle(Paint.Style.FILL);
textPaint.setTextSize(20);
textPaint.setColor(Color.White);
textPaint1.setStyle(Paint.Style.STROKE);
textPaint1.setStrokeWidth(20);
textPaint1.setColor(Color.GREEN);
StaticLayout sl = new StaticLayout(
textLayer.getText(), // - text which will be drawn
textPaint,
boundsWidth, // - width of the layout
Layout.Alignment.ALIGN_CENTER, // - layout alignment
1, // 1 - text spacing multiply
1, // 1 - text spacing add
true); // true - include padding
int boundsHeight = sl.getHeight();
int bmpHeight = (int) (canvasHeight * Math.max(TextLayer.Limits.MIN_BITMAP_HEIGHT,
1.0F * boundsHeight / canvasHeight));
// create bitmap where text will be drawn
Bitmap bmp;
if (reuseBmp != null && reuseBmp.getWidth() == boundsWidth
&& reuseBmp.getHeight() == bmpHeight) {
// if previous bitmap exists, and it's width/height is the same - reuse it
bmp = reuseBmp;
bmp.eraseColor(Color.TRANSPARENT); // erase color when reusing
} else {
bmp = Bitmap.createBitmap(boundsWidth, bmpHeight, Bitmap.Config.ARGB_8888);
}
StaticLayout sl1 = new StaticLayout(
textLayer.getText(), // - text which will be drawn
textPaint1,
boundsWidth, // - width of the layout
Layout.Alignment.ALIGN_CENTER, // - layout alignment
1, // 1 - text spacing multiply
1, // 1 - text spacing add
true); // true - include padding
// calculate height for the entity, min - Limits.MIN_BITMAP_HEIGHT
int boundsHeight1 = sl1.getHeight();
int bmpHeight1 = (int) (canvasHeight * Math.max(TextLayer.Limits.MIN_BITMAP_HEIGHT,
1.0F * boundsHeight1 / canvasHeight));
Bitmap bmp1;
if (reuseBmp != null && reuseBmp.getWidth() == boundsWidth
&& reuseBmp.getHeight() == bmpHeight1) {
// if previous bitmap exists, and it's width/height is the same - reuse it
bmp1 = reuseBmp;
bmp1.eraseColor(Color.TRANSPARENT); // erase color when reusing
} else {
bmp1 = Bitmap.createBitmap(boundsWidth, bmpHeight, Bitmap.Config.ARGB_8888);
}
Canvas canvas = new Canvas(bmp);
canvas.save();
Canvas canvas1 = new Canvas(bmp1);
canvas1.save();
// move text to center if bitmap is bigger that text
if (boundsHeight < bmpHeight) {
//calculate Y coordinate - In this case we want to draw the text in the
//center of the canvas so we move Y coordinate to center.
float textYCoordinate = (bmpHeight - boundsHeight) / 2;
canvas.translate(0, textYCoordinate);
}
// move text to center if bitmap is bigger that text
if (boundsHeight1 < bmpHeight1) {
//calculate Y coordinate - In this case we want to draw the text in the
//center of the canvas so we move Y coordinate to center.
float textYCoordinate = (bmpHeight1 - boundsHeight1) / 2;
canvas1.translate(0, textYCoordinate);
}
//draws static layout on canvas
sl.draw(canvas);
sl1.draw(canvas1);
canvas.restore();
canvas1.restore();
and this to combine the bitmaps
Bitmap bmOverlay = Bitmap.createBitmap(bmp1.getWidth(), bmp1.getHeight(), bmp1.getConfig());
Canvas canvas2 = new Canvas(bmOverlay);
canvas2.drawBitmap(bmp, new Matrix(), null);
canvas2.drawBitmap(bmp1, 0, 0, null);
return bmOverlay;
return bmp;
You need to create two StaticLayout with the same text, but one with the text paint, the other with the stroke paint, then draw at the same position.

android canvas draw text in the triangle

In this Image I want text to totally be in the triangle with CYAN color.
I have created my own ImageView:
public class BookImageView extends android.support.v7.widget.AppCompatImageView {
private static final Float DISCOUNT_SIDE_SIZE = 0.33333F;
private Bitmap bitmap;
private Paint drawPaint = new Paint();
private Paint trianglePaint = new Paint();
{
trianglePaint.setColor(Constants.DISCOUNT_COLOR);
trianglePaint.setStyle(Paint.Style.FILL);
trianglePaint.setShadowLayer(10.0f, 10.0f, 10.0f, Color.parseColor("#7f000000"));
trianglePaint.setAntiAlias(true);
drawPaint.setColor(Color.BLACK);
drawPaint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD));
drawPaint.setShadowLayer(1f, 0f, 1f, Color.BLACK);
}
// Constractors ...
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (bitmap != null) {
Bitmap tempBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.RGB_565);
Canvas tempCanvas = new Canvas(tempBitmap);
tempCanvas.drawBitmap(bitmap, 0, 0, null);
Path path = new Path();
path.setFillType(Path.FillType.EVEN_ODD);
float size = bitmap.getWidth() * DISCOUNT_SIDE_SIZE;
path.lineTo(size, 0);
path.lineTo(0, size);
path.lineTo(0, 0);
path.close();
tempCanvas.drawPath(path, trianglePaint);
float scale = getResources().getDisplayMetrics().density;
drawPaint.setTextSize((int) (14 * scale));
Rect textBounds = new Rect();
drawPaint.getTextBounds("50%", 0, "50%".length(), textBounds);
int x = (int) (size / 2) - textBounds.width() / 2;
int y = (int) (size / 2) - textBounds.height() / 2;
tempCanvas.save();
tempCanvas.rotate(-45, x, y);
tempCanvas.drawText("50%", x, y, drawPaint);
tempCanvas.restore();
setImageDrawable(new BitmapDrawable(getContext().getResources(), tempBitmap));
}
}
#Override
public void setImageBitmap(Bitmap bitmap) {
this.bitmap = bitmap;
invalidate();
}
}
what can I do to solve this problem ?
You can try something like this
1) Measure the width of your text
Use measureText
2) From the point you are drawing calculate the width remaining to draw
3) Now depending on the use case you can curtail the length of text or scale the text as needed
int textWidthRequired = (int) drawPaint.measureText(textToDraw);
int widthRemainingToDraw = totalWidth/2 - textDrawX;
if(textWidthRequired > widthRemainingToDraw){
//handling
}
// draw text
tempCanvas.drawText(textToDraw,textDrawX, textDrawY, drawPaint);
Depending on how high up you want the text to be, you can use properties of similar triangles to first determine the maximum width of the text. In your case, size = the triangle's base, and size = the triangle's height/altitude. Let's define two variables:
Correction: The altitude won't be equal to the base. You'd need to calculate the altitude in order to use the below solution.
float triangleBase = size; // triangle base
float triangleAltitude = size; // Calculate this.
Let's say we want the text to be halfway up the center of the triangle:
float textYHeight = triangleHeight/2;
We figure out the width of the triangle at this point by using the following formula since the sides of similar triangles are proportional:
baseOfTriangleA/baseOfTriangleB = altitudeOfTriangleA/altitudeOfTriangleB;
float triangleWidthAtTextYLocation = (textYHeight * triangleBase)/triangleAltitude;
Now that we know what the width of the triangle is at this location, we can just iterate through different text scales until the text width is less than the value triangleWidthAtTextYlocation.
float scale = getResources().getDisplayMetrics().density;
int scaleFactor = 0;
drawPaint.setTextSize((int) (scaleFactor * scale));
Rect textBounds = new Rect();
drawPaint.getTextBounds("50%", 0, "50%".length(), textBounds);
while(textBounds.length < triangleWidthAtTextYLocation){
// Re-measure the text until it exceeds the width
scaleFactor++;
drawPaint.setTextSize((int) (scaleFactor * scale));
drawPaint.getTextBounds("50%", 0, "50%".length(), textBounds);
}
// Once we know the scaleFactor that puts it over the width of the triangle
// at that location, we reduce it by 1 to be just under that width:
scaleFactor = Maths.abs(scaleFactor - 1);
// final text size:
drawPaint.setTextSize((int) (scaleFactor * scale));

Add text to image in android programmatically

I want to make an application just like opening screen of android.I am dynamically adding images to the rows of tableLayout. I have only defined tableLayout in xml file and remaining code is in java. I have added images successfully but i am not getting any help with setting text of that image (I want to display a text under image) and image to be a specific padding.How to do it?Thanks in advance.
Use the following function to write Text on Images:
private BitmapDrawable writeTextOnDrawable(int drawableId, String text) {
Bitmap bm = BitmapFactory.decodeResource(getResources(), drawableId)
.copy(Bitmap.Config.ARGB_8888, true);
Typeface tf = Typeface.create("Helvetica", Typeface.BOLD);
Paint paint = new Paint();
paint.setStyle(Style.FILL);
paint.setColor(Color.WHITE);
paint.setTypeface(tf);
paint.setTextAlign(Align.CENTER);
paint.setTextSize(convertToPixels(mContext, 11));
Rect textRect = new Rect();
paint.getTextBounds(text, 0, text.length(), textRect);
Canvas canvas = new Canvas(bm);
//If the text is bigger than the canvas , reduce the font size
if(textRect.width() >= (canvas.getWidth() - 4)) //the padding on either sides is considered as 4, so as to appropriately fit in the text
paint.setTextSize(convertToPixels(mContext, 7)); //Scaling needs to be used for different dpi's
//Calculate the positions
int xPos = (canvas.getWidth() / 2) - 2; //-2 is for regulating the x position offset
//"- ((paint.descent() + paint.ascent()) / 2)" is the distance from the baseline to the center.
int yPos = (int) ((canvas.getHeight() / 2) - ((paint.descent() + paint.ascent()) / 2)) ;
canvas.drawText(text, xPos, yPos, paint);
return new BitmapDrawable(getResources(), bm);
}
public static int convertToPixels(Context context, int nDP)
{
final float conversionScale = context.getResources().getDisplayMetrics().density;
return (int) ((nDP * conversionScale) + 0.5f) ;
}
What you can instead do is to put a TextView in overlay to a ImageView using a RelativeLayout :)
Here's Kotlin version Arun's solution:
import org.jetbrains.anko.dip
fun Context.writeTextOnDrawable(drawableId: Int, text: String) =
DrawableUtil.writeTextOnDrawableInternal(this, drawableId, text, 25, -2, 0)
object DrawableUtil {
fun writeTextOnDrawableInternal(context: Context, drawableId: Int, text: String,
textSizeDp: Int, horizontalOffset: Int, verticalOffset: Int): BitmapDrawable {
val bm = BitmapFactory.decodeResource(context.resources, drawableId)
.copy(Bitmap.Config.ARGB_8888, true)
val tf = Typeface.create("Helvetica", Typeface.BOLD)
val paint = Paint()
paint.style = Paint.Style.FILL
paint.color = Color.WHITE
paint.typeface = tf
paint.textAlign = Paint.Align.LEFT
paint.textSize = context.dip(textSizeDp).toFloat()
val textRect = Rect()
paint.getTextBounds(text, 0, text.length, textRect)
val canvas = Canvas(bm)
//If the text is bigger than the canvas , reduce the font size
if (textRect.width() >= canvas.getWidth() - 4)
//the padding on either sides is considered as 4, so as to appropriately fit in the text
paint.textSize = context.dip(12).toFloat()
//Calculate the positions
val xPos = canvas.width.toFloat()/2 + horizontalOffset
//"- ((paint.descent() + paint.ascent()) / 2)" is the distance from the baseline to the center.
val yPos = (canvas.height / 2 - (paint.descent() + paint.ascent()) / 2) + verticalOffset
canvas.drawText(text, xPos, yPos, paint)
return BitmapDrawable(context.resources, bm)
}
}
I m successfully implemented such problem of adding text on image. Just look at following code. First of take one view as Relative layout in that layout take ImageView after that EditText and after that button. Give each of a id. Write a loadBitmapFromView function below.
public Bitmap loadBitmapFromView(View v) {
Bitmap b = Bitmap.createBitmap(v.getWidth(), v.getHeight(), Config.ARGB_8888);
Canvas c = new Canvas(b);
v.layout(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
v.draw(c);
return b;
}
and on click of button.
Bitmap bitmap = loadBitmapFromView(relativeLayout);
File dir = new File(Environment.getExternalStorageDirectory().getAbsolutePath(), "folderName");
if (!dir.exists())
dir.mkdirs();
File file = new File(dir, "capture.jpg");
try {
FileOutputStream fos = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
imageView.setImageBitmap(bitmap);
} catch (Exception e) {
Log.e("ExpressionEditImageActivity", "Error, " + e);
}
Enjoy...
For more reference, refer below screenshot:

Categories

Resources