I have an app where I draw text on bitmap using the position specified by the user. When I ask canvas to draw the text using the x,y coordinates , the text draws in wrong place.
Where I position text Where it draws after I save
My code to save the image
private void drawText(Bitmap bitmap, TextView mText) {
try {
Resources resources = getResources();
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);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.WHITE);
paint.setTextSize(text.getTextSize());
Rect bounds = new Rect();
paint.getTextBounds(mText.getText().toString(), 0, mText.length(), bounds);
canvas.drawText(mText.getText().toString(), text.getX() , text.getY(), paint);
ImageView im = (ImageView) findViewById(R.id.imageView);
im.setImageBitmap(bitmap);
saveBitmap(bitmap);
} catch (Exception e) {
// TODO: handle exception
}
}
Code to drag textview
textView.setOnTouchListener(new View.OnTouchListener() {
int initialX = 0;
int initialY = 0;
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
initialX = (int) event.getX();
initialY = (int) event.getY();
break;
case MotionEvent.ACTION_MOVE:
int currentX = (int) event.getX();
int currentY = (int) event.getY();
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) textView.getLayoutParams();
int left = lp.leftMargin + (currentX - initialX);
int top = lp.topMargin + (currentY - initialY);
int right = lp.rightMargin - (currentX - initialX);
int bottom = lp.bottomMargin - (currentY - initialY);
lp.rightMargin = right;
lp.leftMargin = left;
lp.bottomMargin = bottom;
lp.topMargin = top;
textView.setLayoutParams(lp);
break;
default:
break;
}
return true;
}
});
findViewById(R.id.save).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
drawText(getBitmap(), textView);
}
});
Related
imageView = (ImageView)findViewById(R.id.img);
imageView.setImageResource(R.drawable.aa);
// crash below into bitmap width and height > 0;
bitmap = Bitmap.createBitmap(imageView.getWidth(),imageView.getHeight(), Bitmap.Config.ARGB_8888);
canvas = new Canvas(bitmap);
// imageView.setImageBitmap(bitmap);
dw = imageView.getWidth();
dh = imageView.getHeight();
Log.e("bitmap", "bitmap" + imageView);
Log.e("canvas", "canvas" + canvas);
imageView.setOnTouchListener(this);
//imageView.setOnClickListener(this);
}
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
int x = (int) event.getX();
int y = (int) event.getY();
switch(action){
case MotionEvent.ACTION_DOWN:
if (x >= dh && x < (dh + bitmap.getWidth())
&& y >= dw && y < (dw + bitmap.getHeight())) {
}
break;
}
return true;
}
}
Replace code with below line when you got crash.
imageView.measure(0,0);
bitmap = Bitmap.createBitmap(imageView.getMeasuredWidth(),imageView.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
Also:
dw = imageView.getMeasuredWidth();
dh = imageView.getMeasuredHeight();
I want to map the pixel of bitmap to Imageview x,y coordinate irrespective of Imageview size and Scaletype. e.g If same image is displayed in 3 Imageviews with different size and scaletype when user touch in first imageview on nose of image then I want to add button on nose on remaining two images.
Till now I have managed to detect on what pixel user has touched like this
imageView1.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent event) {
float eventX = event.getX();
float eventY = event.getY();
float[] eventXY = new float[] { eventX, eventY };
Matrix invertMatrix = new Matrix();
((ImageView) view).getImageMatrix().invert(invertMatrix);
invertMatrix.mapPoints(eventXY);
int pixelX = Integer.valueOf((int) eventXY[0]);
int pixelY = Integer.valueOf((int) eventXY[1]);
return false;
}
});
Now... This is how I have converted pixelX,pixelY to imageview coordinates this is working fine if Imageviews are in the same ratio as of original image....
private void addButtonInLayout2(RelativeLayout mRelativeLayout, float pixelX, float pixelY, ImageView mImageView) {
mImageView.setBackgroundColor(Color.GREEN);
final int imageviewWidth = mImageView.getWidth();
final int imageviewHeight = mImageView.getHeight();
Drawable imgDrawable = mImageView.getDrawable();
Bitmap mBitmap = ((BitmapDrawable) imgDrawable).getBitmap();
int buttonX = (int) ((pixelX * imageviewWidth) / (mBitmap.getWidth()));
int buttonY = (int) ((pixelY * imageviewHeight) / (mBitmap.getHeight()));
System.out.println("buttonX =========== " + buttonX);
System.out.println("buttonY =========== " + buttonY);
RelativeLayout.LayoutParams mParams = new RelativeLayout.LayoutParams(50, 50);
mParams.setMargins(buttonX, buttonY, 0, 0);
mRelativeLayout.removeView(yellowButton);
mRelativeLayout.addView(yellowButton, mParams);
mRelativeLayout.invalidate();
}
try this:
LinearLayout ll = new LinearLayout(this);
ll.setOrientation(LinearLayout.VERTICAL);
final ImageView iv0 = new ImageView(this);
iv0.setImageResource(R.drawable.layer0);
ll.addView(iv0, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
final FrameLayout fl = new FrameLayout(this);
final ImageView iv1 = new ImageView(this);
iv1.setImageResource(R.drawable.layer0);
fl.addView(iv1);
ll.addView(fl, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
setContentView(ll);
OnTouchListener l = new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
Matrix m = iv0.getImageMatrix();
Matrix inverse = new Matrix();
m.invert(inverse);
float[] pts = { event.getX(), event.getY() };
inverse.mapPoints(pts);
// get the coordinates for other ImageView
m = iv1.getImageMatrix();
m.mapPoints(pts);
// add the Button
Button b = new Button(fl.getContext(), null, android.R.attr.buttonStyleSmall);
int left = (int) pts[0];
int top = (int) pts[1];
b.setText("pos [" + left + "," + top + "]");
FrameLayout.LayoutParams p = new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, Gravity.NO_GRAVITY);
p.setMargins(left, top, 0, 0);
fl.addView(b, p);
return false;
}
};
iv0.setOnTouchListener(l);
In my application i am able to overlap images one by another, when i drag one image from the group of images the left and right images are also moving on the screen.
How restrict this, below is my code
int cards[] = {R.drawable.c1,R.drawable.c2,R.drawable.c3,R.drawable.c4,R.drawable.c5,R.drawable.c6,
R.drawable.c7,R.drawable.c8,R.drawable.c9,R.drawable.c10,R.drawable.c11,R.drawable.c12,R.drawable.c13};
ImageView[] Images = new ImageView[cards.length];
for (int i = 0; i < cards.length; i++) {
Images[i] = new ImageView(this);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
if (i != 0) {
params.addRule(RelativeLayout.ALIGN_LEFT,i-1);
params.leftMargin= 40;
Images[i].setImageBitmap(BitmapFactory.decodeResource(getResources(), cards[i]));
Images[i].setId(i);
Images[i].setOnTouchListener(this);
layout.addView(Images[i], params);
} else {
Images[i].setImageBitmap(BitmapFactory.decodeResource(getResources(), cards[i]));
Images[i].setId(i);
Images[i].setOnTouchListener(this);
layout.addView(Images[i], params);
}
}
//Ontouch
#Override
public boolean onTouch(View p_v, MotionEvent p_event){
params = (RelativeLayout.LayoutParams)p_v.getLayoutParams();
switch (p_event.getAction()){
case MotionEvent.ACTION_DOWN:
{
status = START_DRAGGING;
imageView1 = new ImageView(this);
imageView1.setImageBitmap(p_v.getDrawingCache());
m_lastTouchX = p_event.getX();
m_lastTouchY = p_event.getY();
break;
}
case MotionEvent.ACTION_UP:
{
status=STOP_DRAGGING;
break;
}
case MotionEvent.ACTION_MOVE:
{
if (status == START_DRAGGING) {
m_dx = p_event.getX() - m_lastTouchX;
m_dy = p_event.getY() - m_lastTouchY;
m_posX = m_prevX + m_dx;
m_posY = m_prevY + m_dy;
System.out.println("Dragging");
params.leftMargin = (int) m_posX;
params.topMargin=(int) m_posY;
p_v.bringToFront();
p_v.setLayoutParams(params);
imageView1.invalidate();
m_prevX = m_posX;
m_prevY = m_posY;
}
break;
}
}
return true;
}
Here is a small snippet to get you going. I added some images into RelativeLayout. The drawing is done in canvas for better performance of dragging. You just need to handle the layout params update MotionEvent.ACTION_UP event:
private ImageView[] Images;
private boolean mDragging = false;
private Rect mImageRect = new Rect();
int mX = 0;
int mY = 0;
private Bitmap mBitmap;
private ImageView mImage;
#Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
mX = (int) ev.getX();
mY = (int) ev.getY();
for (ImageView image : Images) {
image.getHitRect(mImageRect);
if (mImageRect.contains(mX, mY)) {
mDragging = true;
mImage = image;
mBitmap = ((BitmapDrawable) mImage.getDrawable())
.getBitmap();
mImage.setVisibility(View.GONE);
postInvalidate();
break;
}
}
break;
case MotionEvent.ACTION_MOVE:
if (mDragging) {
mX = (int) ev.getX();
mY = (int) ev.getY();
postInvalidate();
}
break;
case MotionEvent.ACTION_UP:
if (mDragging) {
mDragging = false;
mBitmap = null;
mImage.setVisibility(View.VISIBLE);
mImage = null;
}
break;
}
return super.onTouchEvent(ev);
}
#Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
if (mBitmap != null) {
canvas.drawBitmap(mBitmap, mX, mY, null);
}
}
My guess would be that because your images overlap, all three images get the onTouch event and start dragging. You should add some logic that would determine which image is the one that should drag (for example the one that processes the event first) and then START_DRAGGING only that image. You already have a "global" value status. Beside it just add int imageNo and set it in the ACTION_DOWN case statement.
While on the subject: you should only process ACTION_DOWN if status != START_DRAGGING.
I am new to Android. I am trying to implement photo tagging application where we can tag the faces like facebook photo tagging. I am able to find the faces and draw the rectangles over faces.
But I am trying to place an EditText(to write name) at face recognized rectangle when the user touches those rectangles. And once it is done I need to disable the EditText and need show TextView (name). Please find code below and help me.
Code:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.main);
layout = new LinearLayout(this);
LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
myEditTet = new EditText(this);
myView custom = new myView(this);
layout.addView(myEditTet);
myEditTet.setVisibility(View.GONE);
// layout.addView(myTextView);
// myTextView.setVisibility(View.GONE);
layout.addView(custom, params); // Of course, this too
setContentView(layout);
}
private class myView extends View {
private int imageWidth, imageHeight;
private int numberOfFace = 5;
private FaceDetector myFaceDetect;
private FaceDetector.Face[] myFace;
float myEyesDistance;
int numberOfFaceDetected;
Bitmap myBitmap;
public myView(Context context) {
super(context);
// TODO Auto-generated constructor stub
BitmapFactory.Options BitmapFactoryOptionsbfo = new BitmapFactory.Options();
BitmapFactoryOptionsbfo.inPreferredConfig = Bitmap.Config.RGB_565;
myBitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.face3, BitmapFactoryOptionsbfo);
imageWidth = myBitmap.getWidth();
imageHeight = myBitmap.getHeight();
myFace = new FaceDetector.Face[numberOfFace];
myFaceDetect = new FaceDetector(imageWidth, imageHeight,
numberOfFace);
numberOfFaceDetected = myFaceDetect.findFaces(myBitmap, myFace);
}
#Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
canvas.drawBitmap(myBitmap, 0, 0, null);
Paint myPaint = new Paint();
myPaint.setColor(Color.GREEN);
myPaint.setStyle(Paint.Style.STROKE);
myPaint.setStrokeWidth(3);
for (int i = 0; i < numberOfFaceDetected; i++) {
android.media.FaceDetector.Face face = myFace[i];
PointF myMidPoint = new PointF();
face.getMidPoint(myMidPoint);
myEyesDistance = face.eyesDistance();
dx = (int) (myMidPoint.x - myEyesDistance);
dy = (int) (myMidPoint.y - myEyesDistance);
dz = (int) (myMidPoint.x + myEyesDistance);
dt = (int) (myMidPoint.y + myEyesDistance);
canvas.drawRect((int) (myMidPoint.x - myEyesDistance),
(int) (myMidPoint.y - myEyesDistance),
(int) (myMidPoint.x + myEyesDistance),
(int) (myMidPoint.y + myEyesDistance), myPaint);
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
myEditTet.setVisibility(View.VISIBLE);
if (event.getX() > dx && event.getX() < dz && event.getY() > dy
&& event.getY() < dt) {
Log.i("SARDAR", "RECT TOUCH 1111");
}
return super.onTouchEvent(event);
}
}
}
i have done it by this way...
params.setmargin(left,top,right,bottom);
layout.addView(myeditText,params);
arguments are of int types
How do you fix the position of an image drawn onto a canvas with a large scrollable background?
picture this:
the background image is that of a room, the object images are bed, door etc.
the object images are drawn on top of the background.
when i scroll the background, the objects should move with respect to the background image, correct?
the problem is the object images also move but the position doesn't stay the same, i.e they shift from their original positions.
here is my full class implementation.
Bitmap bmImage;
SpriteAnim8 anim;
MThread thread;
PersonAnimated person, person2;
Canvas canvas = new Canvas();
Rect displayRect = null;
Rect scrollRect = null;
int scrollRectX = 0, scrollRectY = 0;
float scrollByX = 0, scrollByY = 0;
float startX = 0, startY = 0;
int initX = 200, initY = 200;
float a = initX, b = initY;
public MGamePanel(Context context) {
super(context);
// adding the callback (this) to the surface holder to intercept events
getHolder().addCallback(this);
// create Person and load bitmap
person = new PersonAnimated(BitmapFactory.decodeResource(getResources(), R.drawable.dad_anim),
10, 200 /* initial position */,
45, 56 /* width and height of sprite */,
5, 10); /* FPS and number of frames in the animation */
// Destination rect for our main canvas draw
displayRect = new Rect(0, 0, SpriteAnim8.displayWidth, SpriteAnim8.displayHeight);
// Scroll rect: this will be used to 'scroll around' over the bitmap
scrollRect = new Rect(0, 0, SpriteAnim8.displayWidth, SpriteAnim8.displayHeight);
// Load a large bitmap
bmImage = BitmapFactory.decodeResource(getResources(), R.drawable.l1_plain);
// create the game loop thread
thread = new MThread(getHolder(), this);
// make the GamePanel focusable so it can handle events
setFocusable(true);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
// at this point the surface is created and we can safely start the game
// loop
thread.setRunning(true);
thread.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
Log.d(TAG, "Surface is being destroyed");
// tell the thread to shut down and wait for it to finish
// this is a clean shutdown
boolean retry = true;
while (retry) {
try {
thread.setRunning(false);
((Activity) getContext()).finish();
retry = false;
} catch (Exception e) {
// try again shutting down the thread
}
}
Log.d(TAG, "Thread was shut down cleanly");
}
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// delegating event handling to the person
startX = event.getRawX();
startY = event.getRawY();
// }
case MotionEvent.ACTION_MOVE:
float x = event.getRawX();
float y = event.getRawY();
// Calculate move update.
mScrollByX = x - mStartX + mOldScrollByX; // move update x increment
mScrollByY = y - mStartY + mOldScrollByX; // move update y increment
onDraw(canvas);
break;
case MotionEvent.ACTION_UP:
mOldScrollByX = mScrollByX;
mOldScrollByY = mScrollByY;
break;
}
return true;
}
public void render(Canvas canvas) {
Paint paint = new Paint();
canvas.drawBitmap(bmImage, scrollRect, displayRect, paint);
person.draw(canvas);
}
#Override
protected void onDraw(Canvas canvas) {
int newScrollRectX = scrollRectX - (int) scrollByX;
int newScrollRectY = scrollRectY - (int) scrollByY;
// Prevent scrolling off the left or right edges of the bitmap.
if (newScrollRectX < 0) {
newScrollRectX = 0;
} else if (newScrollRectX > (bmImage.getWidth() - SpriteAnim8.displayWidth)) {
newScrollRectX = (bmImage.getWidth() - SpriteAnim8.displayWidth);
}
// Prevent scrolling off the top or bottom edges of the bitmap.
if (newScrollRectY < 0) {
newScrollRectY = 0;
} else if (newScrollRectY > (bmImage.getHeight() - SpriteAnim8.displayHeight)) {
newScrollRectY = (bmImage.getHeight() - SpriteAnim8.displayHeight);
}
// set the updated scroll rect coordinates.
scrollRect.set(newScrollRectX, newScrollRectY, newScrollRectX
+ SpriteAnim8.displayWidth, newScrollRectY
+ SpriteAnim8.displayHeight);
// Reset current scroll coordinates to reflect the latest updates so we
// can repeat
scrollRectX = newScrollRectX;
scrollRectY = newScrollRectY;
person.setX(person.getX() + scrollByX);
person.setY(person.getY() + scrollByY);
}
is this correct?
Here is a code how to scroll a picture/image which is drawn on canvas:
//define points on the custome view class level
PointF touchStart = new PointF();
PointF picStart = new PointF();
PointF prevPicStart = new PointF();
Handle the touch and remember the previous poistion of the picture
#Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN: {
touchStart.set(ev.getX(), ev.getY());
break;
}
case MotionEvent.ACTION_MOVE: {
float newX = ev.getX() - touchStart.x + prevPicStart.x;
float newY = ev.getY() - touchStart.y + prevPicStart.y;
//assuming the the picture is bigger than the screen
if ((newX <= 0 && newX > 0 - pic.getWidth() + screenW)){
picStart.x = newX;
}
if ((newY <= 0 && newY > 0 - pic.getHeight() + screenH)){
picStart.y = newY;
}
invalidate();
break;
}
case MotionEvent.ACTION_UP:
prevPicStart.x = picStart.x;
prevPicStart.y = picStart.y;
break;
}
return true;
}
In onDraw
canvas.drawBitmap(pic, picStart.x, picStart.y, null);
Not sure about your code, but you can use a FrameLayout with background that you want for room and add ScrollView as its child, which will contain the other objects which are scrollable.
HTH !