I have a frame layout with a background image.I am using canvas to draw lines on this framelayout.
The issue is , on different screen sizes , the lines are not appearing at the same place.
I tried multiplying the coordinates by the screen density dpi , but its still not working.
Snippet of my canvas code
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.FILL);
bitmap = ((BitmapDrawable) zoom_lay.getBackground()).getBitmap();
mutableBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);
canvas = new Canvas(mutableBitmap);
canvas.drawColor(Color.TRANSPARENT);
zoom_lay.setBackground(new BitmapDrawable(getResources(), mutableBitmap));
final Path pathPolygon_2 = new Path();
pathPolygon_2.reset(); // only needed when reusing this path for a new build
canvas.drawLine(500,500,600,615,paint);
Thank you
Create your layout with the following params:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/mainView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#mipmap/background"
tools:context=".MainActivity">
Can be any type, FrameLayout is just an example. The important part is to set it's width and height to match parent.
From there you can use your code to get the bitmap and draw on it only thing, let's say you want to draw the line horizontally in the center:
canvas.drawLine(0,muteableBitmap.getHeight()/2,muteableBitmap.getWidth(),muteableBitmap.getHeight()/2,paint);
And say you want a line vertically from the center:
canvas.drawLine(muteable.getWidth()/2,0,muteableBitmap.getWidth()/2,muteableBitmap.getHeight,paint);
I've written this manually so it might not compile due to capital letters and such, but it should work
first you need to get the size of the Bitmap, and then calculate the end points of the line according to your needs. For example, if you want to draw a line in the middle of the Bitmap, the Y coordinate is this Bitmap.getHeight() * 0.5f. I hope I can help you.
Bitmap mutableBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);
int height = mutableBitmap.getHeight();
int width = mutableBitmap.getWidth();
float startX = width * 0f;
float startY = height * 0.5f;
float stopX = width * 1f;
float stopY = height * 0.5f;
canvas.drawLine(startX, startY, stopX, stopY, paint);
So, I'm using this library https://github.com/thuytrinh/android-collage-views to add "MultiTouchListener" feature to my ImageView. Basically I let user to modify a photo to his needs using rotation, scale and translation. Now the only problem is how to save it. I did it like this:
Bitmap bitmap = Bitmap.createBitmap(imageContainer.getWidth(), imageContainer.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.drawColor(Color.WHITE);
imageContainer.draw(canvas);
It works, but image is not big enough - it's as big as view on phone so it depends on screen resolution. And I want to "apply" these transformations on given bitmap with full size. And I want transformed image to look like on screen (so it'll need to crop everything out of screen)
I tried the following:
Bitmap newBitmap = Bitmap.createBitmap(image.getWidth(), image.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(newBitmap);
canvas.drawColor(Color.WHITE);
Paint paint = new Paint();
paint.setAntiAlias(true);
canvas.drawBitmap(image, imageView.getMatrix(), paint);
But it doesn't look as expected.
User screen:
And output image (without cropping, because I don't want which side I should crop):
How can I fix this? Is there any solution?
Here is one way to do it, definitely not perfect but should give you a good start :
In this, container refers to the view that contains the transformed ImageView, the phone case on your screenshot and src the raw source bitmap.
First, you need to compute the desired width and height of the output bitmap, i.e the size it would be to make the image fit in it while keeping the ratio of the container :
float containerWidth = containerView.getWidth();
float containerHeight = containerView.getHeight();
float srcWidth = src.getWidth();
float srcHeight = src.getHeight();
float containerRatio = containerWidth / containerHeight;
float srcRatio = srcWidth / srcHeight;
float outputWidth, outputHeight;
if(srcRatio > containerRatio) { //fits in width
outputWidth = srcWidth;
outputHeight = srcWidth / containerRatio;
}
else if(srcRatio < containerRatio) { //fits in height
outputHeight = srcHeight;
outputWidth = srcHeight * containerRatio;
}
else {
outputWidth = srcWidth;
outputHeight = srcHeight;
}
Apply the ratio between container width/height and output width/height to the translation part of the matrix that hold the transformation that the user did
float containerToOutputRatioWidth = outputWidth / containerWidth;
float containerToOutputRatioHeight = outputHeight / containerHeight;
float[] values = new float[9];
transformedImageView.getMatrix().getValues(values);
values[2] = values[2] * containerToOutputRatioWidth;
values[5] = values[5] * containerToOutputRatioHeight;
Matrix outputMatrix = new Matrix();
outputMatrix.setValues(values);
Draw the output bitmap as you were doing with the correct size (outputWidth, outputHeight) and matrix (outputMatrix).
Bitmap newBitmap = Bitmap.createBitmap(Math.round(outputWidth), Math.round(outputHeight), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(newBitmap);
canvas.drawColor(Color.WHITE);
Paint paint = new Paint();
paint.setAntiAlias(true);
canvas.drawBitmap(src, outputMatrix, paint);
.
Warnings
You should be careful about memory allocation, this code will lead to allocate some massive bitmaps, you should implement some kind of limit that get along with your needs. (Also do allocation and drawing in background)
You might need to do some adjustment depending on where you place the image in the first place.
I have created an image picker library in which user can select multiple image for uploading to server.were I'm facing a problem ie, i have to compress the selected images without loosing the quality of image much like in popular application Facebook/Whatsapp etc were images maintain with high quality but less size .i have followed the official doc but it's not really satisfying me.if am uploading size less image only i can load it into UI in a fast manner.
Any suggestions/helps are greatly appreciated.
Here is a great library on GitHub for reducing image size without losing quality.
https://github.com/zetbaitsu/Compressor
Try this:
int width = YourImageView.getWidth();
int height = YourImageView.getHeight();
Bitmap bitmap = Bitmap.createBitmap((int)width, (int)height, Bitmap.Config.ARGB_8888);
float originalWidth = selectedBitmap.getWidth(), originalHeight = selectedBitmap.getHeight();
Canvas canvas = new Canvas(bitmap);
float scale = width/originalWidth;
float xTranslation = 0.0f, yTranslation = (height - originalHeight * scale)/2.0f;
Matrix transformation = new Matrix();
transformation.postTranslate(xTranslation, yTranslation);
transformation.preScale(scale, scale);
Paint paint = new Paint();
paint.setFilterBitmap(true);
canvas.drawBitmap(selectedBitmap, transformation, paint);
Here is my issue, I display in a ListView some Pictures come from web.
I would like to display in my ImageView only a specific area to my picture, without resizing it.
Here is a concret example :
https://docs.google.com/file/d/0B6J9AVdWXjwuWld5dU5CWXFSTjQ/edit?usp=sharing
I think it's possible with a Bitmap method, but I really don't know how to do this...
Thanks for your tips
Yes, the way to do this is to create a Bitmap object out of your source image. Here's an example:
File thumbFile = new File(thumbFileDir, imageName);
//Bitmap source = your image
Bitmap target= Bitmap.createBitmap(thumbSize, thumbSize,Config.ARGB_8888); //in my case the thumb image is square, use your dimensions instead of "thumbSize, thumbSize"
Canvas canvas = new Canvas(target);
float hScale = thumbSize/(float)source.getWidth(); //again, thumb dimensions here
float vScale = thumbSize/(float)source.getHeight(); //and here
float scale = Math.max(hScale, vScale);
Matrix matrix = new Matrix();
matrix.setScale(scale, scale);
matrix.postTranslate(thumbSize/2 - source.getWidth()/2 * scale, thumbSize/2 - source.getHeight()/2 * scale); //and here
canvas.drawColor(Color.BLACK);
canvas.drawBitmap(source, matrix, new Paint());
The "target" object is what you are asking for
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.