I am trying to create an implementation of face-swap, across multiple images. These images are not taken from camera. They are .jpg files on the device.
I need to extract a part of an image of a face, using Google's Face Detection API. For this purpose, I extended ImageView:
public class FaceExtractorImageView extends ImageView {
Bitmap image;
Bitmap origImage;
Context context;
FaceDetector detector;
SparseArray<Face> faces;
List<Rect> faceRects;
boolean changed = false;
Face selectedFace;
public FaceExtractorImageView(Context context) {
super(context);
this.context = context;
detector = new FaceDetector.Builder(context)
.setProminentFaceOnly(false)
.setLandmarkType(FaceDetector.ALL_LANDMARKS)
.build();
faceRects = new ArrayList<>();
//The other constructors do the exact same thing.
}
#Override
public void setImageBitmap(final Bitmap img){
image = img;
selectedFace = null;
if(!changed)
origImage = img;
changed =true;
super.setImageBitmap(img);
faces = detector.detect(new Frame.Builder().setBitmap(image).build());
faceRects.clear();
for(int i=0;i<faces.size();i++)
faceRects.add(getFaceRect(i));
setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
selectedFace = null;
switch(event.getAction()){
case MotionEvent.ACTION_UP:
for(int i=0;i<faceRects.size();i++)
if(faceRects.get(i) {
.contains((int)event.getX(),
(int)event.getY())) {
selectedFace = faces.valueAt(i);
}
invalidate();
}
return true;
}
});
}
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(selectedFace!=null){
Paint p = new Paint();
p.setStyle(Paint.Style.STROKE);
p.setColor(Color.RED);
canvas.drawRect(getFaceRect(selectedFace), p);
}
}
public Face getSelectedFace(){
return selectedFace;
}
public Bitmap getSelectedFaceBitmap() {
if(selectedFace==null)
return null;
int index = faces.indexOfValue(selectedFace);
return getFaceBitmapWithIndex(index);
}
//Returns Bitmap of face with index #index form the currently set image
public Bitmap getFaceBitmapWithIndex(int index) {
return getFaceBitmapWithIndex(image, index);
}
//Returns Bitmap of face with index #index form image #src
public Bitmap getFaceBitmapWithIndex(Bitmap src, int index) {
Rect r = getFaceRect(index);
Bitmap created = Bitmap.createBitmap(src, r.left, r.top, r.width(), r.height());
ImageView v = new ImageView(context);
v.setImageBitmap(created);
//new AlertDialog.Builder(context).setView(v).create().show();
return created;
}
public Rect getFaceRect(Face face){
Rect r= new Rect();
//The constant values used below are for cropping the original image.
r.left = (int) face.getPosition().x + (int) face.getWidth() / 20;
r.top = (int) face.getPosition().y + (int) face.getHeight() / 4;
r.right = r.left + (int) (face.getWidth() * 5.75 / 10);
r.bottom = r.top + (int) (face.getHeight() * 3 / 5);
return r;
}
//Get rect for face at index #index of image #img
public Rect getFaceRect(int index){
Face face = faces.valueAt(index);
if(face==null) {
Log.e("Face not found", "The image in the view does not have a face with index "+index);
return null;
}
return getFaceRect(face);
}
}
The above code does the following:
When the View is touched , it detects if the touch was on a face in the
image. If it was, a cropped box is drawn on the face using
invalidate().
The Rect given by the vision API is cropped using the method
getFaceRect().
The bitmap of the face is given by the method
getFaceBitmapWithIndex(), where the index is required if there are
multiple faces in the image. Otherwise, index is 0.
The problem:
The Rect I use when getting the bitmap of the face is the one given by getFaceRect(). However, I am not able to get the correct area. There is always some offset.
The images explain the situation:
Rect given by the Vision API:
Rect generated by getFaceRect(). This is also drawn in onDraw() when invalidate() is called.
The region that I get when getFaceBitmapWithIndex() is called:
There is something very simple that I'm missing here, but I'm not able to figure what that is. Any help would be appreciated.
I found the bug. Turns out, I didn't take care of the varying dimensions of different images, with respect to the View itself.
So, I put the code after the call to super in setImageBitmap inside the getViewTreeObserver().addOnGlobalLayoutListener and built a new DrawingCache there:
#Override
public void setImageBitmap(final Bitmap img){
if(!changed)
origImage = img;
changed =true;
super.setImageBitmap(img);
getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
buildDrawingCache();
image = getDrawingCache();
selectedFace = null;
faces = detector.detect(new Frame.Builder().setBitmap(image).build());
faceRects.clear();
for (int i = 0; i < faces.size(); i++)
faceRects.add(getFaceRect(i));
setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
selectedFace = null;
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
for (int i = 0; i < faceRects.size(); i++)
if (faceRects.get(i).contains((int) event.getX(), (int) event.getY())) {
//Toast.makeText(context, "Touched", Toast.LENGTH_LONG).show();
selectedFace = faces.valueAt(i);
}
invalidate();
}
return true;
}
});
}
});
}
Related
I'm setting up an eye detection android project and I want to draw probabilities using Canvas, I'm using Firebase ML kit for custom models
I have successfully drawn only one point.
I would like to draw points ( probabilities from tflite model that I have ).
I tried using those functions :
private void useInferenceResult(float[] probabilities) throws IOException {
// [START mlkit_use_inference_result]
String[] result=new String[80];
float x=0;
float y=0;
ArrayList<Point> listpoint= new ArrayList<Point>();
for (int i = 0; i < probabilities.length; i++) {
Log.i("MLKit", String.format("%1.4f", probabilities[i]));
x=probabilities[i];
y=probabilities[i+1];
Point p=new Point(x,y);
i=i+1;
p.setX(x);
p.setY(y);
Log.i("Information1 ","valeur 1 "+p.getX());
listpoint.add(p);
Log.i("Information2 ","valeur 2 "+p.getX());
}
for(int j=0;j<listpoint.size();j++){
Log.e("Information","work");
Log.e("Resultat","point_"+j+"("+listpoint.get(j).getX()+", "+listpoint.get(j).getY()+")");
float xx=listpoint.get(j).getX()*100;
float yy=listpoint.get(j).getY()*100;
drawpoint(image2,0.20958422f * 100,0.6274962f * 100,1);
drawpoint(image2, 0.20460524f * 100,0.6708223f * 100,1);
}
}
//drawpoint function
private void drawpoint(ImageView imageView,float x,float y, int raduis){
BitmapFactory.Options myOptions = new BitmapFactory.Options();
myOptions.inDither = true;
myOptions.inScaled = false;
myOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;// important
myOptions.inPurgeable = true;
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.imgg,myOptions);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.WHITE);
Bitmap workingBitmap = Bitmap.createBitmap(bitmap);
Bitmap mutableBitmap = workingBitmap.copy(Bitmap.Config.ARGB_8888, true);
Canvas canvas = new Canvas(mutableBitmap);
canvas.drawCircle(x,y, raduis, paint);
imageView = (ImageView)findViewById(R.id.imageView);
imageView.setAdjustViewBounds(true);
imageView.setImageBitmap(mutableBitmap);
}
but I didn't get any result just one point drawn.
How can I draw multiples points on imageView?
I solved my problem by changing some lines of code, I declare those variables on the top and I create objects after setContentView:
BitmapFactory.Options myOptions;
Canvas canvas;
Bitmap mutableBitmap;
Bitmap workingBitmap;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn_open= findViewById(R.id.btn_open);
image2= findViewById(R.id.imageView);
myOptions = new BitmapFactory.Options();
bitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.image000880,myOptions);
paint= new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.WHITE);
workingBitmap = Bitmap.createBitmap(bitmap);
mutableBitmap = workingBitmap.copy(Bitmap.Config.ARGB_8888, true);
canvas = new Canvas(mutableBitmap);
private void drawpoint(ImageView imageView,float x,float y, int raduis){
myOptions.inDither = true;
myOptions.inScaled = false;
myOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;// important
myOptions.inPurgeable = true;
// ArrayList<Point> list= new ArrayList<>();
canvas.drawCircle(x,y, raduis, paint);
imageView = (ImageView)findViewById(R.id.imageView);
imageView.setAdjustViewBounds(true);
imageView.setImageBitmap(mutableBitmap);
}
Hope this solution will help others who have the same situation
Simple ImageView Descendent class.
public class CiclesImageView extends AppCompatImageView {
private ArrayList<PointF> theDots = new ArrayList<>();
private Paint paint=new Paint(Paint.ANTI_ALIAS_FLAG);
public CirclesImageView(Context context) {
super(context);
setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction()==MotionEvent.ACTION_DOWN)
drawDot(new PointF(event.getX(),event.getY()));
return performClick();
}
});
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.STROKE);
for (PointF pt:theDots)canvas.drawCircle(pt.x,pt.y,5,paint);
}
public void drawDot(PointF dotPoint){
theDots.add(dotPoint);
invalidate();
}
}
This imageView is used the same way you use any other imageView, except if you touch it, it will draw a circle on itself. If you want to draw your own circles, the drawDot(pointF) is public.
I am new to android programing. I am trying to draw a new bitmap image every time the user touches the screen. With the current code right now, all it does is change where the bitmap is at. It doesn't make a new one. How could I make a new one?? Here is the code:
public class MainDrawingView extends View {
public float eventX;
public float eventY;
public AlertDialog.Builder alertThing;
Context context = getContext();
//Bitmaps
public Bitmap redSquare;
public String x;
public String y;
//Colors
public boolean red = false;
public boolean blue = false;
//Squares
public boolean topRight = false;
public boolean topLeft = false;
public boolean bottomLeft = false;
public boolean bottomRight = false;
public int width = context.getResources().getDisplayMetrics().widthPixels;
public int height = context.getResources().getDisplayMetrics().heightPixels;
public int center = height/2;
public int widthDiv = width/2;
private Paint paint = new Paint();
private Point pointStart = new Point();
private Point pointEnd = new Point();
public MainDrawingView(Context context, AttributeSet attrs){
super(context, attrs);
paint.setAntiAlias(true);
paint.setStrokeWidth(5f);
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
alertThing = new AlertDialog.Builder(context);
//define bitmap
redSquare = BitmapFactory.decodeResource(getResources(), R.drawable.red);
}
#Override
public void onDraw(Canvas canvas){
//canvas.drawPath(path, paint);
canvas.drawLine(pointStart.x, pointStart.y, pointEnd.x, pointEnd.y,paint);
//Makes a straight line go through the center of the screen.
canvas.drawLine(0,height/2.5f, width,height/2.5f,paint);
//Makes a straight line go up and down.
canvas.drawLine(width/2.3f,0, width/2.3f, height,paint);
//Chnages the square colors.
// top left combo
if(topLeft){
if(red){
Toast.makeText(context,"jgjgjgjgjgjgjgjgjjg", Toast.LENGTH_SHORT).show();
new Drawings(redSquare, canvas, eventX, eventY);
}
}
}
#Override
public boolean onTouchEvent(MotionEvent event){
//Gets the coords of the tap
eventX = event.getX();
eventY = event.getY();
int pointX = Math.round(eventX);
int pointY = Math.round(eventY);
x = String.valueOf(eventX);
y = String.valueOf(eventY);
//This is the top left "square"
if(eventY < center && eventX < widthDiv ){
alertThing.setTitle("edit square");
alertThing.setMessage("please choose an option");
alertThing.setPositiveButton("red", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
topLeft = true;
red = true;
invalidate();
}
});
alertThing.setNeutralButton("Chnange color to blue", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
}
});
alertThing.create();
alertThing.show();
}
Toast.makeText(context, "center is :" +x, Toast.LENGTH_SHORT ).show();
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
//Sets a new starting point
pointStart.set(pointX,pointY);
return true;
case MotionEvent.ACTION_UP:
//Contects the points
pointEnd.set(pointX,pointY);
break;
default:
return false;
}
invalidate();
return true;
}
}
Here is the Drawings class that draws the bitmaps:
public class Drawings {
public Drawings(Bitmap bitmap, Canvas canvas,float x, float y){
canvas.drawBitmap(bitmap, x,y,null);
}
}
You really should see what canvas.drawBitmap does. Of course it changes the position, since the touch position changes too.
You create a new bitmap just like you did it when defining bitmap.
But creating new objects in the onDraw will be very slow.
i googled coverflow code i found one useful and work great to me (im not professional in android development ), what i need it.
when click on each image it will stream predetermined mp3 song for each image and another click will stop it ,
so each image will have different mp3 song which all mp3 songs stored in app it self .
public class CoverFlowExample extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
CoverFlow coverFlow;
coverFlow = new CoverFlow(this);
coverFlow.setAdapter(new ImageAdapter(this));
ImageAdapter coverImageAdapter = new ImageAdapter(this);
//coverImageAdapter.createReflectedImages();
coverFlow.setAdapter(coverImageAdapter);
coverFlow.setSpacing(-25);
coverFlow.setSelection(4, true);
coverFlow.setAnimationDuration(1000);
setContentView(coverFlow);
}
public class ImageAdapter extends BaseAdapter {
int mGalleryItemBackground;
private Context mContext;
private FileInputStream fis;
private Integer[] mImageIds = {
R.drawable.aa,
R.drawable.aab,
R.drawable.aabb,
R.drawable.aabbb,
R.drawable.aac,
};
private ImageView[] mImages;
public ImageAdapter(Context c) {
mContext = c;
mImages = new ImageView[mImageIds.length];
}
public boolean createReflectedImages() {
//The gap we want between the reflection and the original image
final int reflectionGap = 4;
int index = 0;
for (int imageId : mImageIds) {
Bitmap originalImage = BitmapFactory.decodeResource(getResources(),
imageId);
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 matrix applied to it.
//We only want the bottom half of the image
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 in the gap
Paint deafaultPaint = new Paint();
canvas.drawRect(0, height, width, height + reflectionGap, deafaultPaint);
//Draw in the reflection
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, 0x70ffffff, 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);
ImageView imageView = new ImageView(mContext);
imageView.setImageBitmap(bitmapWithReflection);
imageView.setLayoutParams(new CoverFlow.LayoutParams(120, 180));
imageView.setScaleType(ScaleType.MATRIX);
mImages[index++] = imageView;
}
return true;
}
public int getCount() {
return mImageIds.length;
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
//Use this code if you want to load from resources
ImageView i = new ImageView(mContext);
i.setImageResource(mImageIds[position]);
i.setLayoutParams(new CoverFlow.LayoutParams(430, 430));
i.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
BitmapDrawable drawable = (BitmapDrawable) i.getDrawable();
drawable.setAntiAlias(true);
return i;
//return mImages[position];
}
/** Returns the size (0.0f to 1.0f) of the views
* depending on the 'offset' to the center. */
public float getScale(boolean focused, int offset) {
/* Formula: 1 / (2 ^ offset) */
return Math.max(0, 1.0f / (float)Math.pow(2, Math.abs(offset)));
}
}
}
I am trying to remove my last path drawn on my canvas. I have tryed so far to add my paths in a ArrayList but I didn't find any method to remove the path easilly from canvas.
public class PaintView extends View {
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mPaint;
private static final int TOUCH_TOLERANCE_DP = 20;
private static final int BACKGROUND = Color.TRANSPARENT;
private List<Point> mPoints = new ArrayList<Point>();
private int mLastPointIndex = 0;
private int mTouchTolerance;
private boolean isPathStarted = false;
private boolean canCreatePoints = true;
private Polygon poly;
private Builder build;
private ArrayList<Polygon> polyList;
private ArrayList<Path> undoPath, redoPath;
public PaintView(Context context) {
super(context);
mCanvas = new Canvas();
mPath = new Path();
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(Color.BLACK);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(12);
mTouchTolerance = dp2px(TOUCH_TOLERANCE_DP);
polyList = new ArrayList<Polygon>();
undoPath = new ArrayList<Path>();
redoPath = new ArrayList<Path>();
}
#Override
protected void onSizeChanged(int width, int height, int oldWidth,
int oldHeight) {
super.onSizeChanged(width, height, oldWidth, oldHeight);
clear();
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(BACKGROUND);
canvas.drawBitmap(mBitmap, 0, 0, null);
canvas.drawPath(mPath, mPaint);
for(Path p : undoPath) {
canvas.drawPath(p, mPaint);
}
for (Point point : mPoints) {
canvas.drawPoint(point.x, point.y, mPaint);
}
}
Below is onTouch method, I create lines using Path when variable canCreatePoints it's true.If canCreatePoints it's false I check in a ArrayList<Polygon> if my touch point is inside a polygon.
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if(canCreatePoints == true)
{
create_point(x,y);
if( mPoints.size() > 1 )
{
// start point
Point p = mPoints.get(mLastPointIndex);
mPath.moveTo(p.x, p.y);
// end point
p = mPoints.get(mLastPointIndex + 1);
mPath.lineTo(p.x, p.y);
mCanvas.drawPath(mPath, mPaint);
undoPath.add(mPath);
mPath.reset();
// increment point index
++mLastPointIndex;
}
}
if(canCreatePoints == false)
{
Points pp = new Points(Math.round(x), Math.round(y));
boolean contains;
for(Polygon tempPoly:polyList){
contains = tempPoly.contains(pp);
if(contains == true)
{
Log.i("TEST","Poligonul contine punctul");
Toast.makeText(getContext(),"Test poly "+polyList.indexOf(tempPoly),
Toast.LENGTH_SHORT).show();
}
}
}
invalidate();
break;
}
return true;
}
private void create_point(float x, float y){
Point p = new Point(Math.round(x),Math.round(y));
mPoints.add(p);
}
Bellow I finnish my polygon form by action of a Button. I create a path from last point to first point and draw it on canvas.
public void finnishDraw(){
if( mPoints.size() > 1 )
{
// start point
Point p = mPoints.get(0);
mPath.moveTo(p.x, p.y);
// end point
p = mPoints.get( mPoints.size() - 1);
mPath.lineTo(p.x, p.y);
mCanvas.drawPath(mPath, mPaint);
mPath.reset();
invalidate();
int x[] = new int[mPoints.size()];
int y[] = new int[mPoints.size()];
build = new Builder();
for(int i=0 ; i<mPoints.size() ; i++)
{
p = mPoints.get(i);
x[i] = p.x;
y[i] = p.y;
build.addVertex(new Points(x[i],y[i]));
Log.i("TEST","Adaug la builder punctele "+x[i]+" si "+y[i]);
}
poly = build.build();
polyList.add(poly);
mPoints.clear();
mLastPointIndex = 0;
}
}
So far I found only a solution with a back-up Bitmap before drawing a line but I didn't understand how it really works.
You can't undo a drawPath on a Canvas. From the documentation:
Via the Canvas, your drawing is actually performed upon an underlying
Bitmap, which is placed into the window.
As you say, you need a backup Bitmap to save the state of the current Bitmap before drawing on it, for example using a Memento pattern.
Take a look at Fast undo/redo for bitmap editor when memory is limited? and Fast undo facility for bitmap editor application (the last one targetting iPhone, but the underlying idea is the same)
Another approach less memory consuming could be saving the state of the objects that you want to draw on your canvas and draw them on demand (when you need to show a partial or a full result).
To remove the last path only apply this function:
public void clearLast(){
if(!paths.isEmpty()) {
backgroundColor = DEFAULT_BG_COLOR;
int size = paths.size();
paths.remove(paths.get(size-1));
normal();
invalidate();
}
}
I develop tile based game to draw i use function canvas.drawBitmap() in each frame function drawBitmap using 400+ times when i use scroll (Gestures) performance is pretty bad.
Can anyone give me advice how to increase performance to make smooth animation.
public class DiamondIsometric implements Render{
private int MapWidth;
private int MapHeight;
private Bitmap _surface;
private Bitmap tempBitmap;
public DiamondIsometric(int MapWidth,int MapHeight,Bitmap _surface)
{
this.MapWidth=MapWidth;
this.MapHeight=MapHeight;
this._surface = _surface;
}
public MapObject[][] BuildMap()
{
int rx;
int ry;
MapObject[][] MapObjects = new MapObject[MapWidth][MapHeight];
for(int x=0;x<MapHeight;x++)
for(int y=0;y<MapWidth;y++)
{
rx=(x-y)*_surface.getWidth()/2;
ry=(x+y)*_surface.getHeight()/2;
MapObject temp = new MapObject(new Point(rx,ry),_surface);
MapObjects[x][y]=temp;
}
return MapObjects;
}
#Override
public void Render(Canvas canvas) {
}
#Override
public void Render(Canvas canvas,MapObject[][] MapObjects)
{
Paint temp = new Paint();
temp.setColor(Color.BLACK);
canvas.drawPaint(temp);
Bitmap toDraw = Bitmap.createBitmap(MapWidth*_surface.getWidth(), MapHeight*_surface.getHeight(), Config.RGB_565);
int bitmapOffsetX,bitmapOffsetY;
canvas.drawBitmap(this.Render2(canvas,MapObjects),0,0,null);
}
public Bitmap Render2(Canvas canvas, MapObject[][] MapObjects)
{
Paint temp = new Paint();
temp.setColor(Color.BLACK);
tempBitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Config.RGB_565);
Canvas wideBMPCanvas = new Canvas(tempBitmap);
int bitmapOffsetX,bitmapOffsetY;
for(int i=0;i<MapObjects.length;i++)
for(int j=0;j<MapObjects[i].length;j++)
{
bitmapOffsetX=(IsometricView.globalAnchor.x % MapObjects[i][j]._bitmap.getWidth());
bitmapOffsetY=(IsometricView.globalAnchor.y % MapObjects[i][j]._bitmap.getHeight());
wideBMPCanvas.drawBitmap(MapObjects[i][j]._bitmap,MapObjects[i][j].coords.x-IsometricView.globalAnchor.x ,MapObjects[i][j].coords.y-IsometricView.globalAnchor.y , null);
}
return tempBitmap;
}
}
Use a game engine like andEngine or libgdx. They use OpenGL rendering which is usually much faster.
Update: If you want not to use OpenGL/game engines you should try to combine tiles into a larger bitmap. Create a larger bitmap and create a new canvas (new Canvas(largeBitmap)) to draw the tile to it. Drawing one larger is faster than drawing multiple smaller ones. For my Game K'UMPA I used a similar approach, which is more complex in detail, because only a small part of the map is visible on the screen.
Maybe you could try to not create a bitmap at each render call.
I assume that you're calling render for each frame:
public class DiamondIsometric implements Render {
private int MapWidth;
private int MapHeight;
private Bitmap _surface;
private Bitmap toDraw;
private Canvas wideBMPCanvas;
public DiamondIsometric(int MapWidth,int MapHeight,Bitmap _surface)
{
this.MapWidth = MapWidth;
this.MapHeight = MapHeight;
this._surface = _surface;
this.toDraw = null;
this.wideBMPCanvas = null;
}
public MapObject[][] BuildMap()
{
int rx;
int ry;
MapObject[][] MapObjects = new MapObject[MapWidth][MapHeight];
for(int x=0;x<MapHeight;x++)
for(int y=0;y<MapWidth;y++)
{
rx=(x-y)*_surface.getWidth()/2;
ry=(x+y)*_surface.getHeight()/2;
MapObject temp = new MapObject(new Point(rx,ry),_surface);
MapObjects[x][y]=temp;
}
return MapObjects;
}
#Override
public void Render(Canvas canvas) { }
#Override
public void Render(Canvas canvas,MapObject[][] MapObjects)
{
Paint temp = new Paint();
temp.setColor(Color.BLACK);
canvas.drawPaint(temp);
if (this.toDraw == null) {
this.toDraw = Bitmap.createBitmap(MapWidth*_surface.getWidth(), MapHeight*_surface.getHeight(), Config.RGB_565);
}
if (this.wideBMPCanvas == null) {
this.wideBMPCanvas = new Canvas(this.toDraw);
}
int bitmapOffsetX,bitmapOffsetY;
for (int i = 0; i < MapObjects.length; i++) {
for(int j = 0; j < MapObjects[i].length; j++)
{
bitmapOffsetX = (IsometricView.globalAnchor.x % MapObjects[i][j]._bitmap.getWidth());
bitmapOffsetY = (IsometricView.globalAnchor.y % MapObjects[i][j]._bitmap.getHeight());
this.wideBMPCanvas.drawBitmap(MapObjects[i][j]._bitmap, MapObjects[i][j].coords.x - IsometricView.globalAnchor.x,
MapObjects[i][j].coords.y - IsometricView.globalAnchor.y, null);
}
}
canvas.drawBitmap(this.toDraw, 0, 0, null);
}
}