Create Bitmap using a String - android

I want to create a Bitmap using the String. The problem is when I assign the Paint and String to the Canvas.
All I see is a dot/black pixel that is created is something wrong with the Configs that I am using?
Here is my code below:
private void createBitmap(){
int textSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 15, getApplicationContext().getResources().getDisplayMetrics());
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setSubpixelText(true);
paint.setStyle(Paint.Style.FILL);
paint.setTextSize(textSize);
paint.setColor(Color.BLACK);
int w = 500, h = 200;
Bitmap.Config conf = Bitmap.Config.ARGB_8888; // see other conf types
Bitmap myBitmap = Bitmap.createBitmap(w, h, conf);
Canvas myCanvas = new Canvas(myBitmap);
myCanvas.drawColor(Color.WHITE, PorterDuff.Mode.CLEAR);
myCanvas.drawText("Just a string", 0, 0, paint);
imageView = new ImageView(this);
imageView.setImageBitmap(myBitmap);
}

The y parameter is actually for the baseline of the text, so you won't really see anything with y == 0. The dot you're seeing is probably the descender of the "g" in "string".
Try changing to
myCanvas.drawText("Just a string", 0, 100, paint);
so at least you can see something.
Note: You are setting the text size based on density, but you are making the bitmap an absolute pixel size, so you are going to have to do some calculation to get the look you want.
Once you have your Paint configured, you can determine the height of the text in pixels by calling getFontMetrics() on the Paint, then looking at the FontMetrics values. ascent will be negative since it's measuring upward, so you can get a rough idea of the height by fm.descent - fm.ascent.
Here's a way to draw your text just below the top edge of the bitmap:
Paint.FontMetrics fm = paint.getFontMetrics();
int baseline = (int) - fm.ascent; // also fm.top instead of fm.ascent
myCanvas.drawText("Just a string", 0, baseline, paint);

Related

Resizing a custom marker on Android maps

Im quite new to Android so forgive me if I have missed something.
I've got the following code which displays a custom marker on maps. This custom marker also has some text on it. It works well up to the point where I want to resize the marker by a certain amount when the text is longer.
The code I originally had for the custom marker was,
private Bitmap drawTextToBitmap(final int mResId, final String mText) {
Resources resources = getResources();
// Get the screen's density scale
float scale = resources.getDisplayMetrics().density;
Bitmap bitmap = BitmapFactory.decodeResource(resources, mResId);
Bitmap.Config bitmapConfig = bitmap.getConfig();
if ( bitmapConfig == null ) {
bitmapConfig = Bitmap.Config.ARGB_8888;
}
bitmap = bitmap.copy(bitmapConfig, true);
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
// Set font color
paint.setColor(Color.WHITE);
// Set font size and scale it
paint.setTextSize((int) (14 * scale));
// Set shadow width
paint.setShadowLayer(1f, 0f, 1f, Color.BLACK);
// Set anti-aliasing
paint.setAntiAlias(true);
// Make font bold
paint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD));
Rect bounds = new Rect();
paint.getTextBounds(mText, 0, mText.length(), bounds);
int x = (bitmap.getWidth() - bounds.width())/2;
int y = ((bitmap.getHeight() + bounds.height())/2)-25;
canvas.drawText(mText, x, y, paint);
return bitmap;
}
How can I resize this bitmap and also increase the font size accordingly without loosing any resolution ? Unfortunately I cant give screenshots due to licensing/permission issues.
Found the solution which was to add the following before creating the canvas.
int newWidth = (int) (origBitmap.getWidth() * scalingFactor);
int newHeight = (int) (origBitmap.getHeight() * scalingFactor);
Bitmap bitmap = Bitmap.createScaledBitmap(origBitmap, newWidth, newHeight, true);
This will scale the bitmap accordingly. I can similarly scale the font using the same scalingFactor.

How might I add a watermark effect to an image in Android?

I have an image with frames and I need to add a watermark effect. How might I do this?
I found great tutorial on Android Image Processing here.
public static Bitmap mark(Bitmap src, String watermark, Point location, Color color, int alpha, int size, boolean underline) {
int w = src.getWidth();
int h = src.getHeight();
Bitmap result = Bitmap.createBitmap(w, h, src.getConfig());
Canvas canvas = new Canvas(result);
canvas.drawBitmap(src, 0, 0, null);
Paint paint = new Paint();
paint.setColor(color);
paint.setAlpha(alpha);
paint.setTextSize(size);
paint.setAntiAlias(true);
paint.setUnderlineText(underline);
canvas.drawText(watermark, location.x, location.y, paint);
return result;
}
Thanks to Pete Houston who shares such useful tutorial on basic image processing.
For others reference, if you want to add the logo of your application (which is in your drawable folder(s)) on top of image use following method:
private Bitmap addWaterMark(Bitmap src) {
int w = src.getWidth();
int h = src.getHeight();
Bitmap result = Bitmap.createBitmap(w, h, src.getConfig());
Canvas canvas = new Canvas(result);
canvas.drawBitmap(src, 0, 0, null);
Bitmap waterMark = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.logo);
canvas.drawBitmap(waterMark, 0, 0, null);
return result;
}
If someone is still searching for this, I found a good solution here
It adds a watermark to the bottom right portion and scales it according to the source image which was exactly what I was looking for.
/**
* Embeds an image watermark over a source image to produce
* a watermarked one.
* #param source The source image where watermark should be placed
* #param watermark Watermark image to place
* #param ratio A float value < 1 to give the ratio of watermark's height to image's height,
* try changing this from 0.20 to 0.60 to obtain right results
*/
public static Bitmap addWatermark(Bitmap source, Bitmap watermark, float ratio) {
Canvas canvas;
Paint paint;
Bitmap bmp;
Matrix matrix;
RectF r;
int width, height;
float scale;
width = source.getWidth();
height = source.getHeight();
// Create the new bitmap
bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG | Paint.FILTER_BITMAP_FLAG);
// Copy the original bitmap into the new one
canvas = new Canvas(bmp);
canvas.drawBitmap(source, 0, 0, paint);
// Scale the watermark to be approximately to the ratio given of the source image height
scale = (float) (((float) height * ratio) / (float) watermark.getHeight());
// Create the matrix
matrix = new Matrix();
matrix.postScale(scale, scale);
// Determine the post-scaled size of the watermark
r = new RectF(0, 0, watermark.getWidth(), watermark.getHeight());
matrix.mapRect(r);
// Move the watermark to the bottom right corner
matrix.postTranslate(width - r.width(), height - r.height());
// Draw the watermark
canvas.drawBitmap(watermark, matrix, paint);
return bmp;
}
And it is well commented which is what is a huge plus!
It seems you are looking for a waterrippleeffect as this one. Checkout the complete source code. Also check the screenshot how does the effect look like.
In Kotlin:
Note: Its just modified code of above answers
private fun mark(src: Bitmap, watermark: String): Bitmap {
val w = src.width
val h = src.height
val result = Bitmap.createBitmap(w, h, src.config)
val canvas = Canvas(result)
canvas.drawBitmap(src, 0f, 0f, null)
val paint = Paint()
paint.color = Color.RED
paint.textSize = 10f
paint.isAntiAlias = true
paint.isUnderlineText = true
canvas.drawText(watermark, 20f, 25f, paint)
return result
}
val imageBitmap = mark(yourBitmap, "Your Text")
binding.meetProofImageView.setImageBitmap(imageBitmap)
You can use androidWM to add a watermark into your image, even with invisible watermarks:
add dependence:
dependencies {
...
implementation 'com.huangyz0918:androidwm:0.2.3'
...
}
and java code:
WatermarkText watermarkText = new WatermarkText(“Hello World”)
.setPositionX(0.5)
.setPositionY(0.5)
.setTextAlpha(100)
.setTextColor(Color.WHITE)
.setTextFont(R.font.champagne)
.setTextShadow(0.1f, 5, 5, Color.BLUE);
WatermarkBuilder.create(this, backgroundBitmap)
.loadWatermarkText(watermarkText)
.getWatermark()
.setToImageView(backgroundView);
You can easily add an image type watermark or a text watermark like this, and the library size is smaller than 30Kb.
I tried a few libraries mentioned in other posts, like this, but unfortunately it is missing, and not downloadable now. So I followed AndroidLearner 's answer above, but after tweaking the code a little bit, for those of you who are having trouble rotating the watermark, and what values are valid for the various methods of Paint class, so that the text shows rotated at an angle(like most of the company watermarks do), you can use the below code.
Note that, w and h are the screen width and height respectively, which you can calculate easily, there are tons of ways you can find on stackoverflow only.
public static Bitmap waterMarkBitmap(Bitmap src, String watermark) {
int w = src.getWidth();
int h = src.getHeight();
Bitmap mutableBitmap = Utils.getMutableBitmap(src);
Bitmap result = Bitmap.createBitmap(w, h, mutableBitmap.getConfig());
Canvas canvas = new Canvas(result);
canvas.drawBitmap(src, 0f, 0f, null);
Paint paint = new Paint();
paint.setColor(Color.RED);
paint.setTextSize(92f);
paint.setAntiAlias(true);
paint.setAlpha(70); // accepts value between 0 to 255, 0 means 100% transparent, 255 means 100% opaque.
paint.setUnderlineText(false);
canvas.rotate(45, w / 10f, h / 4f);
canvas.drawText(watermark, w / 10f, h / 4f, paint);
canvas.rotate(-45, w / 10f, h / 4f);
return result;
}
It rotates the text watermark by 45 degrees, and places it at the centre of the bitmap.
Also note that, in case you are not able to get watermark, it might be the case that the bitmap you are using as source is immutable. For this worst case scenario, you can use below method to create a mutable bitmap from an immutable one.
public static Bitmap getMutableBitmap(Bitmap immutableBitmap) {
if (immutableBitmap.isMutable()) {
return immutableBitmap;
}
Bitmap workingBitmap = Bitmap.createBitmap(immutableBitmap);
return workingBitmap.copy(Bitmap.Config.ARGB_8888, true);
}
I found above method inside here. I have tested using both the methods in my application, and it works perfectly after I added above tweaks. Try it and let me know if it works or not.
use framelayout. put two imageviews inside the framelayout and specify the position of the watermark imageview.

Center text on a bitmap

I'm trying to draw a text on the center of a bitmap however I can't do it even though I used align.center. The code is:
public Bitmap drawTextToBitmap(Context gContext, String gText) {
Resources resources = gContext.getResources();
float scale = resources.getDisplayMetrics().density;
Bitmap bitmap =
BitmapFactory.decodeResource(resources, R.drawable.blank_marker);
android.graphics.Bitmap.Config bitmapConfig =
bitmap.getConfig();
// set default bitmap config if none
if(bitmapConfig == null) {
bitmapConfig = android.graphics.Bitmap.Config.ARGB_8888;
}
// resource bitmaps are imutable,
// so we need to convert it to mutable one
bitmap = bitmap.copy(bitmapConfig, true);
Canvas canvas = new Canvas(bitmap);
// new antialised Paint
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
// text color - #3D3D3D
paint.setColor(Color.rgb(61, 61, 61));
// text size in pixels
paint.setTextSize((int) (25 * scale));
// text shadow
paint.setShadowLayer(1f, 0f, 1f, Color.WHITE);
// draw text to the Canvas center
Rect bounds = new Rect();
paint.setTextAlign(Align.CENTER);
paint.getTextBounds(gText, 0, gText.length(), bounds);
int x = (bitmap.getWidth() - bounds.width())/2;
int y = (bitmap.getHeight() + bounds.height())/2;
canvas.drawText(gText, x * scale, y * scale, paint);
return bitmap;
}
What am I doing wrong?
It's a lot more straightforward than you think.
Draw the text at half the Bitmap's width and height (center point) in combination with Paint.setTextAlign(Align.CENTER).
The alignment property will take care of the rest.
I guess none of the answers given above are good enough so I post my answer. Try it out guys, it will work on all devices and is not complex at all:
String text = "Text"; //your string
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(activity.getResources().getColor(R.color.white));
paint.setTextSize(30);
// draw text to the Canvas center
Rect boundsText = new Rect();
paint.getTextBounds(text, 0, text.length(), boundsText);
int x = (bitmap.getWidth() - boundsText.width()) / 2;
int y = (bitmap.getHeight() + boundsText.height()) / 2;
canvas.drawText(text, x, y, paint);
Where is the text drawing? The issue might be since you changed the text align to Align.CENTER. Your code calculating x and y assumes the text rendering is using Align.LEFT, I believe.
Either use setTextAlign(Align.CENTER) and render at the actual bitmap center, or use setTextAlign(Align.LEFT) and use the current x and y calculations you are using.

Determine width and height of a bitmap

I am using the following code snippet to create a bitmap with text.
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Style.FILL);
paint.setColor(fontColor);
paint.setTextSize(fontSize);
canvas.drawText("My Text", x, y, paint);
Here's the catch. How do I determine the size of the Bitmap to use in the canvas beforehand? For instance if I want a bitmap with "Hello World!" on it, I want to find the width and height of it even before I draw the text on the canvas.
You can tyr this:
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
Rect bounds = new Rect();
paint.setStyle(Style.FILL);
paint.setColor(fontColor);
paint.setTextSize(fontSize);
paint.getTextBounds("My Text", 0, "My Text".length(), bounds);
int width = bounds.width();
int height = bounds.height();
canvas.drawText("My Text", x, y, paint);
Try this, it loads the bitmap, then gets the heigth and width, then you just have to draw it. Replace bitmap with your image name
bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.bitmap);
bitmapHeigth = bitmap.getHeigth();
bitmapWidth = bitmap.getWidth();

Getting rendered text height, which is equivalent to rendered text width using paint.measureText

I have the following code to draw text.
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
paint.setTextSize(400);
paint.setColor(Color.WHITE);
paint.setAntiAlias(true);
paint.setTextAlign(Align.LEFT);
paint.setStyle(Style.FILL);
String text = "698";
Rect bounds = new Rect();
paint.getTextBounds(text, 0, text.length(), bounds);
int textWidth = bounds.width();
int textHeight = bounds.height();
Bitmap originalBitmap = Bitmap.createBitmap(textWidth,
textHeight, Bitmap.Config.ARGB_8888);
Canvas singleUseCanvas = new Canvas(originalBitmap);
singleUseCanvas.drawColor(Color.BLUE);
singleUseCanvas.drawText(text, 0, textHeight, paint);
canvas.drawBitmap(originalBitmap, 0, 0, null);
}
I am getting undesired outcome, which its right and bottom sides are being cropped.
I avoid right side cropping, by using
float textWidth = paint.measureText(text);
Bitmap originalBitmap = Bitmap.createBitmap((int)(textWidth + 0.5),
textHeight, Bitmap.Config.ARGB_8888);
I am getting the following improvement
Yet. My bottom still being cropped. May I know what is the correct way to obtained rendered text height, which is analogy to rendered text width using paint.measureText?
I think i would be helpful to have a look at this post:
Android Paint: .measureText() vs .getTextBounds()
It have a good survey about sizing of rendered text and also text height which is your concern.

Categories

Resources