Reputation: 1
I'm coding photo app that overlap user's photo on transparent frame. i show user's bitmap on imageview and frame on other imageview (relative layout). bitmap can zoom, drag. After that, user can merge 2 bitmap on this imageviews as seeing on screen. My problem is getting possition of bitmap inside imageview when zoom and drag. i wanna get coordinate of bitmap inside imageview to draw by canvas (merge bitmap and frame)
My Code
public class Overlapping extends Activity implements OnTouchListener {
private Matrix matrix = new Matrix();
private Matrix matrixTest = new Matrix();
private Matrix savedMatrix = new Matrix();
// we can be in one of these 3 states
private static final int NONE = 0;
private static final int DRAG = 1;
private static final int ZOOM = 2;
private int mode = NONE;
private PointF start = new PointF();
private PointF start1Up = new PointF();
private PointF mid = new PointF();
private float oldDist = 1f;
private float d = 0f;
private float[] lastEvent = null;
public static float newRot = 0f; // lấy góc quay về
public static float scale;
float deltax, deltay = 0;
ImageView view, topView;
TextView textInfo;
Button btSave;
Bitmap bm1 = null;
Bitmap bm2 = null;
Bitmap newBitmap = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_overlapping);
textInfo = (TextView) findViewById(R.id.textInfo);
view = (ImageView) findViewById(R.id.bottomFrame);
topView = (ImageView) findViewById(R.id.topFrame);
bm1 = BitmapFactory.decodeResource(getResources(), R.drawable.test4);
bm2 = BitmapFactory.decodeResource(getResources(), R.drawable.home_frame);
Bitmap bitmap = Bitmap.createScaledBitmap(
bm1,
(int) (bm1.getWidth() / 1.6), (int) (bm1.getHeight() / 1.6),
false
);
view.setImageBitmap(bitmap);
view.setOnTouchListener(this);
btSave = (Button) findViewById(R.id.btSave);
btSave.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Bitmap processedBitmap = ProcessingBitmap();
topView.setImageBitmap(processedBitmap);
}
});
}
private Bitmap ProcessingBitmap() {
try {
int w = bm2.getWidth();
int h = bm2.getHeight();
Config config = bm1.getConfig();
if (config == null) {
config = Bitmap.Config.ARGB_8888;
}
newBitmap = Bitmap.createBitmap(w, h, config); // dùng cái này tùy
Canvas newCanvas = new Canvas(newBitmap);
Drawable drawables = view.getDrawable();
Rect rectImage = drawables.getBounds();
float[] newvalues = new float[9];
matrixTest.getValues(newvalues);
Bitmap rotatedBitmap = Bitmap.createBitmap(
bm1,
0,
0,
bm1.getWidth(),
bm1.getHeight(),
matrix,
true
);
topView.setImageBitmap(rotatedBitmap);
newCanvas.drawBitmap(
rotatedBitmap,
(int) (deltax * rotatedBitmap.getWidth() / view.getWidth() / 1.45),
(int) (deltay * rotatedBitmap.getHeight() / view.getHeight() / 1.45),
null
);
newCanvas.drawBitmap(bm2, 0, 0, null);
} catch (Exception e) {
e.printStackTrace();
}
return newBitmap;
}
@Override
public boolean onTouch(View v, MotionEvent event) {
// handle touch events here
ImageView view = (ImageView) v;
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
savedMatrix.set(matrix);
start.set(event.getX(), event.getY());
mode = DRAG;
lastEvent = null;
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = spacing(event);
if (oldDist > 10f) {
savedMatrix.set(matrix);
midPoint(mid, event);
mode = ZOOM;
}
lastEvent = new float[4];
lastEvent[0] = event.getX(0);
lastEvent[1] = event.getX(1);
lastEvent[2] = event.getY(0);
lastEvent[3] = event.getY(1);
d = rotation(event);
break;
case MotionEvent.ACTION_UP:
break;
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
lastEvent = null;
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG) {
matrix.set(savedMatrix);
float dx = event.getX() - start.x;
float dy = event.getY() - start.y;
matrix.postTranslate(dx, dy);
} else if (mode == ZOOM) {
float newDist = spacing(event);
if (newDist > 10f) {
matrix.set(savedMatrix);
scale = (newDist / oldDist);
matrix.postScale(scale, scale, mid.x, mid.y);
}
if (lastEvent != null && event.getPointerCount() == 2) {
newRot = rotation(event);
float r = newRot - d;
float[] values = new float[9];
matrix.getValues(values);
float tx = values[2];
float ty = values[5];
float sx = values[0];
float xc = (view.getWidth() / 2) * sx;
float yc = (view.getHeight() / 2) * sx;
matrix.postRotate(r, tx + xc, ty + yc);
matrixTest.set(matrix);
}
}
break;
}
view.setImageMatrix(matrix);
return true;
}
/**
* Determine the space between the first two fingers
*/
private float spacing(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return FloatMath.sqrt(x * x + y * y);
}
/**
* Calculate the mid point of the first two fingers
*/
private void midPoint(PointF point, MotionEvent event) {
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
point.set(x / 2, y / 2);
}
/**
* Calculate the degree to be rotated by.
*
* @param event
* @return Degrees
*/
private float rotation(MotionEvent event) {
double delta_x = (event.getX(0) - event.getX(1));
double delta_y = (event.getY(0) - event.getY(1));
double radians = Math.atan2(delta_y, delta_x);
return (float) Math.toDegrees(radians);
}
}
XML:
<RelativeLayout
android:id="@+id/RelativeLayout1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="left" >
<ImageView
android:id="@+id/bottomFrame"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_margin="10dp"
android:paddingTop="2dip"
android:src="@drawable/em"
android:scaleType="matrix" />
<ImageView
android:id="@+id/topFrame"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_margin="10dp"
android:scaleType="fitStart"
android:src="@drawable/home_frame" />
</RelativeLayout>
Upvotes: 0
Views: 1265
Reputation: 1308
If you really want it like we see on screen and don't care about the resolution of merged image, you can export your parent view in to an image like this:
void saveButtonPressed() {
View parentView = findViewById(R.id.RelativeLayout1); //from your XML
parentView.setDrawingCacheEnabled(true);
Bitmap final_bitmap = parentView.getDrawingCache();
String root = Environment.getExternalStorageDirectory().toString();
String imageName = "Image-" + System.currentTimeMillis() + ".jpg";
saveImage(final_bitmap, root, imageName);
}
public static boolean saveImage(Bitmap finalBitmap, String root, String image_name) {
File myDir = new File(root);
if (!myDir.exists()) {
myDir.mkdirs();
}
File file = new File(myDir, image_name);
if (file.exists()) file.delete();
Log.i("LOAD", root + image_name);
try {
FileOutputStream out = new FileOutputStream(file);
finalBitmap.compress(Bitmap.CompressFormat.JPEG, 90, out);
out.flush();
out.close();
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
This will export entire canvas of parent view in to an image. Make sure you are managing required permissions.
Upvotes: 0
Reputation: 2042
I had the same need in my app. here is what I've done, hope it helps you.
public Bitmap mergeBitmaps() {
Bitmap baseBitmap = ((BitmapDrawable) image.getDrawable()).getBitmap();
Bitmap mergedBitmap = Bitmap.createBitmap(baseBitmap.getWidth(), baseBitmap.getHeight(), baseBitmap.getConfig());
Canvas canvas = new Canvas(mergedBitmap);
canvas.drawBitmap(baseBitmap, new Matrix(), null);
for (ImageView sticker: stickers) {
float viewSizeRatio = (float) sticker.getWidth() / image.getWidth();
float bitmapSizeRatio = (float) sticker.getDrawable().getBounds().width() / image.getDrawable().getBounds().width();
float ratioFactor = viewSizeRatio / bitmapSizeRatio;
float deltaX = sticker.getTranslationX()* ratioFactor;
float deltaY = sticker.getTranslationY()* ratioFactor;
float scaleX = sticker.getScaleX()* ratioFactor;
float scaleY = sticker.getScaleY()* ratioFactor;
float rotation = sticker.getRotation();
Matrix matrix = new Matrix();
matrix.postScale(scaleX, scaleY);
matrix.postRotate(rotation);
matrix.postTranslate(deltaX, deltaY);
Bitmap stickerBitmap = ((BitmapDrawable) sticker.getDrawable()).getBitmap();
canvas.drawBitmap(stickerBitmap, matrix, null);
}
return mergedBitmap;
}
there is a base ImageView (the larger one) named "image" that is in a RelativeLayout, & the other ImageViews named "stickers" are being added to that relative layout in coordinate {0,0}. They will be dragged, scaled & rotated by user. finally you can get their translation & merge theme with base image in a bitmap with canvas.
Upvotes: 1
Reputation: 9926
try to create one single bitmap from the multiple images.
You can try to do it with the raw data, by extracting the pixel data from the images as 32-bit int ARGB pixel arrays, merge in one big array, and create a new Bitmap, using the methods of the Bitmap class like copyPixelsToBuffer(), createBitmap() and setPixels().
you can also do it by using directly compressed format data and streams and the methods of the BitmapFactory class like decodeByteArray().
If you aren't using too many images at once you can use separate ImageViews and recycle them/reload the resources.
public static Bitmap mergeImage(Bitmap b1, Bitmap b2)
{
Bitmap mBitmap = Bitmap.createBitmap(b1.getWidth(), b1.getHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(mBitmap);
int adWDelta = (int)(b1.getWidth() - b2.getWidth())/2 ;
int adHDelta = (int)(b1.getHeight() - b2.getHeight())/2;
canvas.drawBitmap(b1, 0, 0, null);
canvas.drawBitmap(b2, adWDelta, adHDelta, null);
return mBitmap;
}
Upvotes: 0