I have bitmap that need to draw to canvas. The image is of a fixed size, but the canvas will change according to the user's screen size and density (bitmap coule be larger/smaller than the canvas).
I need to draw the bitmap to canvas scaling all the way into the canvas size (without distorting the image), I have done the code as below but the bitmap still filling only a portion of the screen.
Rect dest = new Rect(0, 0, drawCanvas.getWidth(), drawCanvas.getHeight());
Paint paint = new Paint();
paint.setFilterBitmap(true);
drawCanvas.drawBitmap(canvasBitmap, null, dest, paint);
May I know if anybody can shed light on a good solution? Thanks.
This example is in javascript but it should still help you out scale an image
jsFiddle : https://jsfiddle.net/CanvasCode/7oghuwe2/3/
javascript
var canvas1 = document.getElementById('canvas1');
var context1 = canvas1.getContext('2d')
var canvas2 = document.getElementById('canvas2');
var context2 = canvas2.getContext('2d');
var image1 = new Image();
image1.src = "http://media.giphy.com/media/iNk83OBPzlA8o/giphy.gif";
image1.onload = function () {
context1.fillStyle = "#F00";
context1.fillRect(0, 0, canvas1.width, canvas1.height);
context2.fillStyle = "#00F";
context2.fillRect(0, 0, canvas2.width, canvas2.height);
ratio(context1, canvas1, image1);
ratio(context2, canvas2, image1);
}
function ratio(context1, canvas1, image1) {
var imageRatio = image1.width / image1.height;
var newHeight = canvas1.width / imageRatio;
var newWidth = canvas1.height * imageRatio;
var heightDiff = newHeight - canvas1.height;
var widthDiff = newWidth - canvas1.width;
if (widthDiff >= heightDiff) {
context1.drawImage(image1, 0, 0, canvas1.width, canvas1.width / imageRatio);
} else {
context1.drawImage(image1, 0, 0, canvas1.height * imageRatio, canvas1.height);
}
}
Basically you need to calculate what the width would be if you scaled the image by the canvas height and what the height would be if you scale the image by the canvas width, and which ever is smaller, then you scale by that dimension.
The reason why it might not work for you might be because the function drawBitmap() ignores the density of the bitmap. The following is from the documentation.
public void drawBitmap (Bitmap bitmap, Rect src, Rect dst, Paint
paint)
This function ignores the density associated with the bitmap. This is
because the source and destination rectangle coordinate spaces are in
their respective densities, so must already have the appropriate
scaling factor applied.
What you could do is use public void drawBitmap (Bitmap bitmap, Matrix matrix, Paint paint) instead. First you need to map the source Matrix with the desination Matrix. You do this via Matrix.setRectToRect() or Matrix.setPolyToPoly(). This will give you an accurate mapping. Just make sure you map them correctly, otherwise things will be distorted.
For more info refer here: What code should I use with 'drawMatrix.setPolyToPoly' to manipulate and draw just a rectangular part of a bitmap, rather than the entire bitmap?
Related
I have a custom view on which I draw bordered rectangles like so :
protected void onDraw(Canvas cv) {
Paint p = new Paint();
p.setStrokeWidth(5);
p.setColor(Color.LTGRAY);
p.setStyle(Paint.Style.FILL);
for (Rect rect : rects) {
cv.drawRect(rect.left, rect.top, rect.right, rect.bottom, p);
}
p.setColor(Color.BLACK);
p.setStyle(Paint.Style.STROKE);
for (Rect rect : rects) {
cv.drawRect(rect.left, rect.top, rect.right, rect.bottom, p);
}
}
When the user has modified this view by interacting with it, it is time to save it to the sqlite database, as well as a thumbnail of it, the purpose of which is to add a thumbnail of each specific view to a listview, when the user wants to retrieve a specific one.
All of this works perfectly, with the exception of the thumbnail process : some, but not all, of the black lines are lost, every other pixel is correct, and the scaling is correct too.
view.setDrawingCacheEnabled(true);
Bitmap original = view.getDrawingCache();
int w = original.getWidth();
int h = original.getHeight();
float scaling = 100f / Math.max(w, h);
Bitmap b = Bitmap.createScaledBitmap(original, Math.round(scaling * w), Math.round(scaling * h), false);
The bitmap is wrong at this specific point, whether it is created with the above code, with the ThumbnailUtils class, or with a android.graphic.Matrix to handle the scaling.
Without scaling, the bitmap is always right.
Here is a screenshot of the view, composed of four rectangles (square ones, in this case), and of the erroneous thumbnail generated by the above code.
If anyone has a lead, thanks a lot.
I trying to achieve water reflection effect on bitmap. As I saw some apps called water reflection. I know how to do the reflection of the image but the wave on the image is what making me confused on how it is done.
see this image for example
I did many apps on bitmap manipulation but this is quite hard to achieve.
So any idea on where to start. Just an idea to start can be helpful.
For any one needed, I tried some simple tricks to get as closer as water reflection effect. It is not great but it looks fine to me.
I used two methods
Bitmap reflection method (give bitmap as a parameter)
public static Bitmap Reflection(Bitmap imageBitmap) {
int width = imageBitmap.getWidth();
int height = imageBitmap.getHeight();
Matrix matrix = new Matrix();
matrix.preScale(1, -1);
Bitmap reflectionImage = Bitmap.createBitmap(imageBitmap, 0,
0, width, height , matrix, false);
Bitmap newbit=Bitmap.createScaledBitmap(reflectionImage, reflectionImage.getWidth()/8, reflectionImage.getHeight()/8, true);
Bitmap newbit1=Bitmap.createScaledBitmap(newbit, newbit.getWidth()*8, newbit.getHeight()*8, true);
Bitmap scalednew=Bitmap.createScaledBitmap(newbit1, width, height-(height/4), true);
Bitmap newscaledone=overlay(scalednew);
reflectionImage=newscaledone;
Bitmap reflectedBitmap = Bitmap.createBitmap(width,
(height + height), Config.ARGB_8888);
Canvas canvas = new Canvas(reflectedBitmap);
canvas.drawBitmap(imageBitmap, 0, 0, null);
Paint defaultPaint = new Paint();
canvas.drawRect(0, height, width, height, defaultPaint);
canvas.drawBitmap(reflectionImage, 0, height , null);
Paint paint = new Paint();
paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
canvas.drawRect(0, height, width, reflectedBitmap.getHeight()
, paint);
return reflectedBitmap;
}
Bitmap overlay method. I am taking a wave bitmap with some opacity to overlay on the reflected image. So that it may look like water.
Bitmap wavebitmap=BitmapFactory.decodeResource(getResources(), R.drawable.waves1);
private static Bitmap overlay( Bitmap bmp2) {
Bitmap bmp1=WaterReflectionMainActivity.wavebitmap;
Bitmap bmp1new =Bitmap.createScaledBitmap(bmp1, bmp2.getWidth(), bmp2.getHeight(), true);
Bitmap bmOverlay = Bitmap.createBitmap(bmp1new.getWidth(), bmp1new.getHeight(), bmp1new.getConfig());
Canvas canvas = new Canvas(bmOverlay);
canvas.drawBitmap(bmp2, new Matrix(), null);
canvas.drawBitmap(bmp1new, new Matrix(), null);
return bmOverlay;
}
Well this is my version of water effect, I know this looks shit.
So if anyone still got some better effect please share your code .
thank you
Tutorial related to this: http://www.xaraxone.com/webxealot/workbook34/page_4.htm
Also have a read at this question: Add water effect on bitmap android.
Have a read at both of them, i hope you will get an idea from this
You may also want to look through these: 1, 2, 3
This is just an idea but basically, what you need is to apply a deformation on the bottom part of the image, meaning that for each pixel on the bottom half, you compute a position to get it's color from the top picture.
Here's a pseudo code to give you a hint :
for (int x = 0; x < width; x++) {
for (int y = 0; y < img.height; y++) {
// Compute a position on the original image
// tweak the values heres to get the effect you want
sourceX = x + (int) (cos(10000.0 / y) * 20);
sourceY = img.height - y - 1 +(int)( sin(y* 0.5) * 20);
// Maybe check the range of sourceX and source Y
int color = img.getColor(sourceX, sourceY)
outptut.setColor(x, y + img.height, color);
}
}
you can achieve this by masking may this code will help you
http://www.seeques.com/22527681/how-can-do-this-effect-in-android-may-be-android-bitmap-masking-effect.html
EDIT
also see this for reference
http://code.google.com/p/android-ripple-demo/source/browse/#svn%2Ftrunk%2Fsrc%2Fcom%2Fkesalin%2FRippleDemo
https://github.com/esteewhy/whater
http://code.google.com/p/waterrippleeffect/source/browse/trunk/src/com/example/android/watereffect/WaterEffectView.java?r=3
android noise effect on bitmap
I want to implement cover flow as below
I have tried Carousel, but its not the same thing. Did some google search was not able to find something even near to the cover flow implemented in given example.
Definitely have a look at this, FancyCoverFlow.
There is a demo app for it in the Play store as well that shows the reflection requirement you'd like.
have you tried this:
blog post
public Bitmap getRefelection(Bitmap image) {
// The gap we want between the reflection and the original image
final int reflectionGap = 0;
// Get you bit map from drawable folder
Bitmap originalImage = image;
int width = originalImage.getWidth();
int height = originalImage.getHeight();
// This will not scale but will flip on the Y axis
Matrix matrix = new Matrix();
matrix.preScale(1, -1);
// Create a Bitmap with the flip matix applied to it.
// We only want the bottom half of the image
/*if(bitmapWithReflection!=null && !bitmapWithReflection.isRecycled()){
bitmapWithReflection.recycle();
bitmapWithReflection=null;
}*/
Bitmap reflectionImage = Bitmap.createBitmap(originalImage, 0,
height / 2, width, height / 2, matrix, false);
// Create a new bitmap with same width but taller to fit reflection
Bitmap bitmapWithReflection = Bitmap.createBitmap(width,(height + height / 2), Config.ARGB_8888);
// Create a new Canvas with the bitmap that's big enough for
// the image plus gap plus reflection
Canvas canvas = new Canvas(bitmapWithReflection);
// Draw in the original image
canvas.drawBitmap(originalImage, 0, 0, null);
//Draw the reflection Image
canvas.drawBitmap(reflectionImage, 0, height + reflectionGap, null);
// Create a shader that is a linear gradient that covers the reflection
Paint paint = new Paint();
LinearGradient shader = new LinearGradient(0,
originalImage.getHeight(), 0, bitmapWithReflection.getHeight()
+ reflectionGap, 0x40ffffff, 0x00ffffff, TileMode.CLAMP);
// Set the paint to use this shader (linear gradient)
paint.setShader(shader);
// Set the Transfer mode to be porter duff and destination in
paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
// Draw a rectangle using the paint with our linear gradient
canvas.drawRect(0, height, width, bitmapWithReflection.getHeight()
+ reflectionGap, paint);
if(originalImage!=null && originalImage.isRecycled()){
originalImage.recycle();
originalImage=null;
}
if(reflectionImage!=null && reflectionImage.isRecycled()){
reflectionImage.recycle();
reflectionImage=null;
}
return bitmapWithReflection;
}
Have you gone through the Android Coverflow which is bit different form the Carousel which you want.
I made cover flow widget which is not dependent on gallery.
You can find it here. I will add some samples later.
http://applm.github.io/ma-components/
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.
I'm doing my own pixel calculations for drawing on the screen, and have a sprite bitmap (4x2 images in one file). Each image is 100x100, and the overall file is 400x200. Using the following method my drawing is not pulling the right section of the bitmap, and the placement on the scren isn't quite right:
public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint)
Since: API Level 1
Draw the specified bitmap, scaling/translating automatically to fill
the destination rectangle. If the source rectangle is not null, it
specifies the subset of the bitmap to draw.
Note: if the paint contains a maskfilter that generates a mask which
extends beyond the bitmap's original width/height (e.g.
BlurMaskFilter), then the bitmap will be drawn as if it were in a
Shader with CLAMP mode. Thus the color outside of the original
width/height will be the edge color replicated.
This function ignores the density associated with the bitmap. This is
because the source and destination rectangle coordinate spaces are in
their respective densities, so must already have the appropriate
scaling factor applied.
Parameters
bitmap > The bitmap to be drawn
src > May be null. The subset of the bitmap to be drawn
dst > The rectangle that the bitmap will be scaled/translated to fit into
paint > May be null. The paint used to draw the bitmap
Rect source = new Rect();
source.left = (this.currentFrame % 4) * 100;
source.right = source.left + 100;
source.top = (this.currentFrame / 4) * 100;
source.bottom = source.top + 100;
Rect dest = new Rect();
dest.top = (int) top;
dest.left = (int) left;
dest.right = dest.left + 100;
dest.bottom = dest.top + 100;
// draw current frame onto canvas
//canvas.drawBitmap(pics[this.currentFrame], left, top, painter);
canvas.drawBitmap(pics[0], source, dest, painter);
The documentation explicity says densities are ignored, but why is my image being scaled?
As per Renard
How exactly are you loading pics[0]? Have you tried getResources().openRawResource(imageId)?
This solved my problem.