I searched through this site to find out how to rotate a image back and forth and came up with my own with the help of other post on this site, it works great, the only problem is now I got it working so it rotates back and forth the way I like it, how the heck do I now position it on the screen?
heres the code so far:
private Bitmap ray;
private int mRot = -33;
private boolean goRight = true;
void onRotDraw(Canvas canvas)
{
int width = ray.getWidth();
int height = ray.getHeight();
if (mRot > 30){
goRight = false;
}
if (mRot < -30){
goRight = true;
}
if (goRight){
mRot += 1;
}else
{
mRot -= 1;
}
canvas.rotate(mRot,width / 2,height / 2);
this.Draw_Sprite(canvas, 0, mRot );
}
public void Draw_Sprite(Canvas c, int whatever, int rot) {
//rotating image back and forth
int width = ray.getWidth();
int height = ray.getHeight();
Rect src = new Rect(width - width, height - height, width, height);
Rect dst = new Rect(width - width, height - height, width, height);
c.drawBitmap(this.ray, src, dst, null);
}
Usually with drawBitmap I use it to position my images but this one uses the src and dst instead for the size of the rectangle, so now it works great but how would I change the position on the screen from 0,0 to where I want it to go?
this was taken partially or mostly from this post:
Sprite Rotation in Android using Canvas.DrawBitmap. I am close, what am I doing wrong?
Which gave me all I needed to get this going except how to set the x and y position on the screen, any help with this would be greatly appreciated, I've been wrecking my brains out trying to find a way to get this set the x and y positions with no luck and its probably something simple.
Thanks in advance.
This is a piece of code from that other post you referenced:
Rect src = new Rect(0, 0, width, height);
Rect dst = new Rect(x, y, x + width, y + height);
It's the x and y in the dst Rect that determine the location of the bitmap.
Your code:
Rect src = new Rect(width - width, height - height, width, height);
Rect dst = new Rect(width - width, height - height, width, height);
Is going to always draw it at 0, 0 because width - width will be 0 and height - height will be 0.
Related
I want to place the watermark on the bottom right of the picture. But, in some mobiles it is coming perfectly and in some mobile phones, the watermark is coming on the whole image.
Here is my code:
rotatedBitmap = Bitmap.createBitmap(loadedImage, 0, 0,
loadedImage.getWidth(), loadedImage.getHeight(),
rotateMatrix, false);
int w = rotatedBitmap.getWidth();
int h = rotatedBitmap.getHeight();
Bitmap result = Bitmap.createBitmap(w, h, rotatedBitmap.getConfig());
Canvas canvas = new Canvas(result);
canvas.drawBitmap(rotatedBitmap, 0, 0, null);
Bitmap waterMark = BitmapFactory.decodeResource(getResources(), R.drawable.watermark2);
int ww = waterMark.getWidth();
int hh = waterMark.getHeight();
canvas.drawBitmap(waterMark,(w-ww),(h-hh), null);
EDIT: Here are the screenshots of the result. In second picture, the watermark is coming perfectly and in first picture, it is coming on the whole picture.
Make use of aspect ratio. Calculate aspect ratio of device and accordingly calculate appropriate size for your water mark.
How to calculate aspect ratio?
Check for width and height of screen whichever is bigger divide it by smaller one
example:
if(screen_width > screen_height){
aspectRatio = screen_width/screen_height
}else{
aspectRatio = screen_height/screen_width
}
now that you have calculated aspect ratio multiply it with size of you water mark and scale it accordingly.
like:
float ww = watermark.getWidth()*aspectRatio;
float wh = watermark.getHeight()*aspectRatio;
and use these values.
Hope this helps...
Just Give ratio and you go to go,try changing ratio values that best fit for your src bitmap .
Embeds an image watermark over a source image to produce a
watermarked one.
#param source The source image where watermark should be placed
#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(Context context, Bitmap source, float ratio)
{
Canvas canvas;
Paint paint;
Bitmap bmp;
Matrix matrix;
RectF r;
int width, height;
float scale;
Bitmap waterMark = BitmapFactory.decodeResource(context.getResources(), R.drawable.watermark3x);
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());
// Move the watermark to the bottom left corner
// matrix.postTranslate(0 , height - r.height());
// Move the watermark to the top-left corner
// matrix.postTranslate(0 ,0);
// Move the watermark to the top right corner
// matrix.postTranslate(width - r.width(), 0l̥);
// Draw the watermark
canvas.drawBitmap(waterMark, matrix, paint);
return bmp;
}
I've been searching here about cut bitmaps in android, however I could not make it work for me.
I would like to cut off some part of one specific bitmap, but I want to do that starting from center to the bottom of my image.
I already tried to use:
createBitmap(android.graphics.Bitmap source, int x, int y, int width, int height)
However, it always start to cut my image from the TOP, even changing x and y values.
I want to cut my bitmap as below blue square.
Someone have any idea about how to cut my bitmap?
You should take a look at this:
private Bitmap cropBitmap1()
{
Bitmap bmp2 = BitmapFactory.decodeResource(this.getResources(), R.drawable.image1);
Bitmap bmOverlay = Bitmap.createBitmap(320, 480, Bitmap.Config.ARGB_8888);
Paint p = new Paint();
p.setXfermode(new PorterDuffXfermode(Mode.CLEAR));
Canvas c = new Canvas(bmOverlay);
c.drawBitmap(bmp2, 0, 0, null);
c.drawRect(30, 30, 100, 100, p);
return bmOverlay;
}
Link: Source
Try this:
Bitmap source = BitmapFactory.decodeResource(getResources(),
R.drawable.ic_launcher);
int width = source.getWidth();
int height = source.getHeight();
int required = 25;// 25 pixels width and height
int startX = (width - required) / 2;
int startY = (height - required) / 2;
Bitmap resized = Bitmap.createBitmap(source, startX, startY, required,
required);
The only relevant part is the startX and startY calculations. The code asumes that you need a 25*25 pixels image.
I'm trying to scale and rotate in single operation before creting the final bitmap but the preRotate, postConcat doesn't seem to work.
Bitmap bmp = ... original image ...
Matrix m = new Matrix()
m.setScale(x, y);
m.preRotate(degrees, (float) width / 2, (float) height / 2);
Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), m, true);
It only applies the scale and not rotation.
The answer was given, but to make things more clear to anyone reading this:
1) if you wish to perform ONE transformation in your bitmap, you CAN use SET (setRotate, setScale etc).
But note that any call to a "set" method OVERRIDES other transformations. It's like a new matrix. That's why OP's rotation was not working. These calls are not performed line by line. It's like they are scheduled to be done at runtime by the GPU when the new bitmap is being drawn. It's like when resolving your matrix, GPU rotated it, but then, created a scaled new one, ignoring previous matrix.
2) if you wish to perform more then one transformation, then you MUST use "pre" or "post" methods.
And what is the difference between a postRotate and a preRotate, for example? Well, this matrix math stuff is not my strength, but what I know is that the graphic cards make these transformations using matrix multiplication. It seems to be way more efficient. And as far as I remember from school, when multiplicating matrices the order IS important. A X B != B X A. So, scale a matrix and then rotate it is different from rotate and then scale it.
BUUUUT, as far as the final result in the screen is the same, we high level programmers usually do not need to know these differences. The GPU does.
Well, in that rare cases when you are performing really complicated matrix operations, and results are not what you expected or the performance is terrible and you need to deeply understand these methods to fix your code, well, then android documentation can not be of much help anyway. Instead, a good Linear Algebra book would be your best friend. ;)
This is the code
public class Bitmaptest extends Activity {
#Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
LinearLayout linLayout = new LinearLayout(this);
// load the origial BitMap (500 x 500 px)
Bitmap bitmapOrg = BitmapFactory.decodeResource(getResources(),
R.drawable.android);
int width = bitmapOrg.getWidth();
int height = bitmapOrg.getHeight();
int newWidth = 200;
int newHeight = 200;
// calculate the scale - in this case = 0.4f
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
// createa matrix for the manipulation
Matrix matrix = new Matrix();
// resize the bit map
matrix.postScale(scaleWidth, scaleHeight);
// rotate the Bitmap
matrix.postRotate(45);
// recreate the new Bitmap
Bitmap resizedBitmap = Bitmap.createBitmap(bitmapOrg, 0, 0,
newWidth, newHeight, matrix, true);
// make a Drawable from Bitmap to allow to set the BitMap
// to the ImageView, ImageButton or what ever
BitmapDrawable bmd = new BitmapDrawable(resizedBitmap);
ImageView imageView = new ImageView(this);
// set the Drawable on the ImageView
imageView.setImageDrawable(bmd);
// center the Image
imageView.setScaleType(ScaleType.CENTER);
// add ImageView to the Layout
linLayout.addView(imageView,
new LinearLayout.LayoutParams(
LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT
)
);
// set LinearLayout as ContentView
setContentView(linLayout);
}
}
If you face the issue of OutOfMemory with above answers, than use below:
Bitmap MyFinalBitmap = Bitmap.createBitmap(CurrentBitmap, 0, 0,CurrentBitmap.getWidth()/2, CurrentBitmap.getHeight()/2,matrix, true);
Canvas holds a matrix stack und you can use it with the methods:
Canvas.save()
Doc:
/**
* Saves the current matrix and clip onto a private stack.
*
* Subsequent calls to translate,scale,rotate,skew,concat or clipRect,
* clipPath will all operate as usual, but when the balancing call to
* restore() is made, those calls will be forgotten, and the settings that
* existed before the save() will be reinstated.
*
* #return The value to pass to restoreToCount() to balance this save()
*/
Canvas.restore()
Doc:
/**
* This call balances a previous call to save(), and is used to remove all
* modifications to the matrix/clip state since the last save call. It is
* an error to call restore() more times than save() was called.
*/
example:
A custom View(Android) which looks like a rotary knob(e.g. potentiometer)
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
viewX = getWidth(); //views width
viewY = getHeight(); //views height
setMeasuredDimension(widthMeasureSpec, heightMeasureSpec); //a must call for every custom view
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
double tempAngel = 3.6 * barValue;
int deltaX = bitmap.getWidth() / 2;
int deltaY = bitmap.getHeight() / 2;
...
canvas.save();
canvas.translate(viewX / 2, viewY / 2); //translate drawing point to center
canvas.rotate((float) tempAngel); //rotate matrix
canvas.save(); //save matrix. your drawing point is still at (viewX / 2, viewY / 2)
canvas.translate(deltaX * -1, deltaY * -1); //translate drawing point a bit up and left to draw the bitmap in the middle
canvas.drawBitmap(bitmap, 0,0, bitmapPaint); // draw bitmap to the tranlated point at 0,0
canvas.restore(); //must calls...
canvas.restore();
}
All of the previous answer assume that this change to the bitmap is being made in a view. However in my case I was making the change to be saved out. Figured I would answer it for those in a similar boat.
There are two ways to do translation. Below dx is the translation in the X axis, and dy is the translation in the Y axis. The other variables should be self explanatory.
1 - Translation within the image (without rotation)
val newBitmap = Bitmap.createBitmap(originalBitmap, dx, dy, newWidth, newHeight, matrix, false)
2 - Complex matrix
matrix.postTranslate(dx, dy)
val newBitmap = Bitmap.createBitmap(newWidth, newHeight, Bitmap.Config.ARGB_8888)
val canvas = Canvas(newBitmap)
canvas.drawBitmap(originalBitmap, matrix, null)
Matrix rotateMatrix = new Matrix();
rotateMatrix.postRotate(rotation);
rotatedBitmap = Bitmap.createBitmap(loadedImage, 0, 0,loadedImage.getWidth(), loadedImage.getHeight(),rotateMatrix, false);
Refer to the following code, seems to work. In your code you are defining Matrix as m but referring to it as matrix
public class FourthActivity extends Activity {
private static final int WIDTH = 50;
private static final int HEIGHT = 50;
private static final int STRIDE = 64;
private static int[] createColors() {
int[] colors = new int[STRIDE * HEIGHT];
for (int y = 0; y < HEIGHT; y++) {
for (int x = 0; x < WIDTH; x++) {
int r = x * 255 / (WIDTH - 1);
int g = y * 255 / (HEIGHT - 1);
int b = 255 - Math.min(r, g);
int a = Math.max(r, g);
colors[y * STRIDE + x] = (a << 24) | (r << 16) | (g << 8) | b;
}
}
return colors;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main2);
final ImageView view1 = (ImageView) findViewById(R.id.imageView1);
int[] colors = createColors();
final Bitmap bmp1 = Bitmap.createBitmap(colors, 0, STRIDE, WIDTH, HEIGHT,
Bitmap.Config.ARGB_8888);
view1.setImageBitmap(bmp1);
Button button = (Button) findViewById(R.id.button1);
button.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View v) {
Matrix matrix = new Matrix();
matrix.setScale(2, 2);
matrix.preRotate(45, (float) WIDTH / 2, (float) HEIGHT / 2);
Bitmap bmp2 = Bitmap.createBitmap(bmp1, 0, 0,
bmp1.getWidth(), bmp1.getHeight(), matrix, true);
ImageView view2 = (ImageView) findViewById(R.id.imageView2);
view2.setImageBitmap(bmp2);
}
});
}
}
Use matrix to scale area of original bitmap to 50% and compress bitmap until it's size < 200k
Compress bitmap to a specific byte size in Android
I'm making a game for Android and I need to rotate an image. When I rotate it obviously it's dimensions change. For example when it's rotated 45 degrees (it's square but I'd like this to work for any rectangle so it's a more general solution) it's width and height become the length of the diagonal, which is longer than the original. After some algebra you can work out that the scale factor is sqrt(2). But the only way I know of to rotate a bitmap is with a matrix. Ex:
matrix.postRotate(degrees);
rotated = Bitmap.createBitmap(mBitmap, 0, 0, mBitmap.getWidth(), mBitmap.getHeight(), matrix, true);
Using this method the size of the bitmap remains constant so to fit the rotated image in the content of the image must shrink. Which causes my problem.
What I have now should work but when run doesn't. Probably because it's overly complex, never the less, here it is:
float totalRotated = 0;
public void rotate(float degrees){
if(mBitmap != null){
float increment = (float)((mBitmap.getWidth()/45.0)*(Math.sqrt(2)-1));
totalRotated += degrees;
totalRotated -= (float)((int)totalRotated/360)*360;
matrix.reset();
matrix.setRotate(totalRotated);
rotated = Bitmap.createBitmap(mBitmap, 0, 0, mBitmap.getWidth(), mBitmap.getHeight(), matrix, true);
rotated = Bitmap.createScaledBitmap(rotated, (int)(mBitmap.getWidth()+(((Math.abs(Math.abs(((int)totalRotated%90)-45)-45)))*increment)), (int)(mBitmap.getHeight()+(((Math.abs(Math.abs(((int)totalRotated%90)-45)-45)))*increment)), true);
}
}
Using the Log.d function I was able to determine that the dimensions set in the last statement are what I expect them to be but the image doesn't change size. Since this doesn't even work, I need a better way to do this or a way to fix my method. Also my method only works for squares. So, how can I do this?
EDIT:
My method does work, I just didn't call setBounds() This can't be the only way to do it though, this is so inefficient.
It's not clear what you're looking for, so here's a function based on yours that attempts to compute the proper width and height of the new bitmap and do the rotation by creating just a single bitmap.
float totalRotated = 0;
public void rotate(float degrees){
if(mBitmap != null){
// compute the absolute rotation
totalRotated = (totalRotated + degrees) % 360;
// precompute some trig functions
double radians = Math.toRadians(totalRotated);
double sin = Math.abs(Math.sin(radians));
double cos = Math.abs(Math.cos(radians));
// figure out total width and height of new bitmap
int newWidth = mBitmap.getWidth() * cos + mBitmap.getHeight() * sin;
int newHeight = mBitmap.getWidth() * sin + mBitmap.getHeight() * cos;
// set up matrix
matrix.reset();
matrix.setRotate(totalRotated);
// create new bitmap by rotating mBitmap
rotated = Bitmap.createBitmap(mBitmap, 0, 0,
newWidth, newHeight, matrix, true);
}
}
I tried Gabe's solution and got the same errors that Ramesh and Regis got. This worked for me:
double radians = Math.toRadians(totalRotated);
double sin = Math.abs(Math.sin(radians));
double cos = Math.abs(Math.cos(radians));
// figure out total width and height of new bitmap
final int width = mBitmap.getWidth();
final int height = mBitmap.getHeight();
final int newWidth = (int) (width * cos + height * sin);
final int newHeight = (int) (width * sin + height * cos);
// set up matrix
final Matrix tf = new Matrix();
tf.postRotate((float) Math.toDegrees(radians), width / 2, height / 2);
tf.postTranslate(
(newWidth - width) / 2,
(newHeight - height) / 2);
// create new bitmap by rotating mBitmap with canvas
final Bitmap rotatedBmp = Bitmap.createBitmap(
newWidth, newHeight, Bitmap.Config.ARGB_8888);
final Canvas canvas = new Canvas(rotatedBmp);
canvas.drawBitmap(mBitmap, tf, null);
I'm writing a Music application and I have already gotten the album arts. However, they came up in various sizes. So, how do I standardized the size of the returned bitmap ?
You'd do something like this:
// load the origial BitMap (500 x 500 px)
Bitmap bitmapOrg = BitmapFactory.decodeResource(getResources(),
R.drawable.android);
int width = bitmapOrg.width();
int height = bitmapOrg.height();
int newWidth = 200;
int newHeight = 200;
// calculate the scale - in this case = 0.4f
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
// createa matrix for the manipulation
Matrix matrix = new Matrix();
// resize the bit map
matrix.postScale(scaleWidth, scaleHeight);
// recreate the new Bitmap
Bitmap resizedBitmap = Bitmap.createBitmap(bitmapOrg, 0, 0,
width, height, matrix, true);
Or you could scale the bitmap to the required size when you draw it on the canvas:
From the android documentation:
drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint)
Draw the specified bitmap, scaling/translating automatically to fill the destination rectangle.
Make src null and dst is a Rect the size/position you want it on the canvas, set up like
Rect rect = new Rect(0, 0, width, height)
canvas.drawBitmap(bitmap, null, rect)
In my experience the code in the accepted answer does not work, at least on some platforms.
Bitmap.createBitmap(bitmapOrg, 0, 0, width, height, matrix, true);
will give you a downsampled image at the full size of the original - so just a blurry image.
Interestingly enough, the code
Bitmap resizedBitmap = Bitmap.createScaledBitmap(square, (int) targetWidth, (int) targetHeight, false);
also gives the blurry image. In my case it was necessary to do this:
// RESIZE THE BIT MAP
// According to a variety of resources, this function should give us pixels from the dp of the screen
// From http://stackoverflow.com/questions/4605527/converting-pixels-to-dp-in-android
float targetHeight = DWUtilities.convertDpToPixel(80, getActivity());
float targetWidth = DWUtilities.convertDpToPixel(80, getActivity());
// However, the above pixel dimension are still too small to show in my 80dp image view
// On the Nexus 4, a factor of 4 seems to get us up to the right size
// No idea why.
targetHeight *= 4;
targetWidth *= 4;
matrix.postScale( (float) targetHeight / square.getWidth(), (float) targetWidth / square.getHeight());
Bitmap resizedBitmap = Bitmap.createBitmap(square, 0, 0, square.getWidth(), square.getHeight(), matrix, false);
// By the way, the below code also gives a full size, but blurry image
// Bitmap resizedBitmap = Bitmap.createScaledBitmap(square, (int) targetWidth, (int) targetHeight, false
I don't have a further solution on this yet, but hopefully this is helpful to someone.