android Camera2 API + TextureView overlay for drawing on camera preview - android

So, I need to overlay the camera2 preview and draw a rectangle on the preview video image by layering a transparent overlay on top. I started with a basic Camera2 code here: https://github.com/googlesamples/android-Camera2Basic
the above use TextureView for camera preview.
Next, I added the following class to project
private class CustomView extends SurfaceView {
private final Paint paint;
private final SurfaceHolder mHolder;
private final Context context;
public CustomView(Camera2BasicFragment context) {
super(context.getActivity().getBaseContext());
mHolder = getHolder();
mHolder.setFormat(PixelFormat.TRANSPARENT);
this.context = context.getActivity().getBaseContext();
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.STROKE);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
invalidate();
if (mHolder.getSurface().isValid()) {
final Canvas canvas = mHolder.lockCanvas();
Log.d("touch", "touchRecieved by camera");
if (canvas != null) {
Log.d("touch", "touchRecieved CANVAS STILL Not Null");
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
canvas.drawColor(Color.TRANSPARENT);
canvas.drawCircle(event.getX(), event.getY(), 100, paint);
mHolder.unlockCanvasAndPost(canvas);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
Canvas canvas1 = mHolder.lockCanvas();
if(canvas1 !=null){
canvas1.drawColor(0, PorterDuff.Mode.CLEAR);
mHolder.unlockCanvasAndPost(canvas1);
}
}
}, 1000);
}
mHolder.unlockCanvasAndPost(canvas);
}
}
return false;
}
}
I need some help in making this work.. Obviously the new class is not used yet. I also need to update the overlay xml to add a second transparent TextureView on top of the camera preview one. Here is my original layout:
Would be very appreciated if anyone can tell me how to make the new class work, and tell me what to add to the layout.
here is fragment_camera2_basic.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.android.camera2basic.AutoFitTextureView
android:id="#+id/texture"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true" />
<FrameLayout
android:id="#+id/control"
android:layout_width="match_parent"
android:layout_height="112dp"
android:layout_alignParentBottom="true"
android:layout_alignParentStart="true"
android:background="#color/control_background">
<Button
android:id="#+id/picture"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="#string/picture" />
<ImageButton
android:id="#+id/info"
android:contentDescription="#string/description_info"
style="#android:style/Widget.Material.Light.Button.Borderless"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|right"
android:padding="20dp"
android:src="#drawable/ic_action_info" />
</FrameLayout>
</RelativeLayout>
and activity_camera.xml
<?xml version="1.0" encoding="utf-8"?><!--
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000"
tools:context="com.example.android.camera2basic.CameraActivity" />

Add
<LinearLayout
android:id="#+id/surface"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" />
Within the fragment. I've added a RelativeLayout around AutoFitTextureView and FrameLayout, but not sure if that is needed.
Change onCreateView to
View view = inflater.inflate(R.layout.fragment_camera2_basic, container, false);
LinearLayout surface = (LinearLayout)view.findViewById(R.id.surface);
surface.addView(new CustomView(this));
return view;

Related

Why are buttons making my canvas drawing like hexagon shape in Android?

I have a strange problem I'm creating a canvas drawing app in Android that has lots of buttons in xml file. The problems is when I draw a circle with all those buttons included in the file it's never a smooth circle it's full of corners like hexagon shape but when I exclude buttons may be leaving in one or two, it draws a perfect smooth circle. I have tried to split the file into three so I've included them using but still same result. Can someone please enlighten me what am I do wrong.
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<!--First Draw -->
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:openDrawer="start">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<ImageButton
android:id="#+id/nav_one"
android:layout_width="30dp"
android:layout_height="60dp"
android:layout_marginTop="100dp"
android:layout_marginBottom="100dp"
android:background="#drawable/ic_tab_res_bkg"/>
<ImageButton
android:id="#+id/nav_two"
android:layout_width="30dp"
android:layout_height="60dp"
android:layout_marginTop="200dp"
android:background="#drawable/ic_tab_tools_bkg"/>
</LinearLayout>
<FrameLayout
android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<!-- The navigation drawer -->
<ListView android:id="#+id/resource_bank"
android:layout_width="350dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:choiceMode="singleChoice"
android:divider="#android:color/background_light"
android:dividerHeight="0dp"
android:background="#f4f1f1"
/>
<ListView android:id="#+id/tools"
android:layout_width="350dp"
android:layout_height="match_parent"
android:layout_gravity="end"
android:choiceMode="singleChoice"
android:divider="#android:color/background_light"
android:dividerHeight="0dp"
android:background="#dedada"/>
</android.support.v4.widget.DrawerLayout>
<RelativeLayout
android:id="#+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center" >
<xxxxx.xxxxxx.xxxx.xxxxxx.DrawView
android:id="#+id/canvas_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignBottom="#+id/canvas_view">
<!-- Pen icons -->
<include layout="#layout/activity_pen_color" android:id="#+id/pen_color" />
<include layout="#layout/activity_pen_style" android:id="#+id/pen_style" />
<!-- Navigation bar icons -->
<ImageView
android:id="#+id/icon_bar"
android:layout_width="match_parent"
android:layout_height="70dp"
android:layout_gravity="bottom"
android:background="#drawable/icon_bar_bkg"
/>
<Button
android:id="#+id/ic_select"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginLeft="150dp"
android:layout_marginTop="60dp"
android:elevation="1dp"
android:background="#drawable/ic_select_bkg"/>
<TextView
android:id="#+id/text_select"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="150dp"
android:layout_marginTop="90dp"
android:text="Select"
android:textColor="#color/colorAccent"
/>
<Button
android:id="#+id/ic_pens"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginLeft="200dp"
android:layout_marginTop="60dp"
android:elevation="1dp"
android:background="#drawable/ic_pen_bkg"/>
<TextView
android:id="#+id/text_pens"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="200dp"
android:layout_marginTop="90dp"
android:text="Pen"
android:textColor="#color/colorAccent"
/>
</FrameLayout>
</RelativeLayout>
My DrawView
public class DrawView extends View {
private Paint drawPaint, canvasPaint;
private Canvas drawCanvas;
private Bitmap canvasBitmap;
private SparseArray<Path> paths;
public DrawView(Context context) {
super(context);
setupDrawing();
}
public DrawView(Context context, AttributeSet attrs) {
super(context, attrs);
setupDrawing();
}
public DrawView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setupDrawing();
}
private void setupDrawing() {
paths = new SparseArray<>();
drawPaint = new Paint();
drawPaint.setColor(Color.BLACK);
drawPaint.setAntiAlias(true);
drawPaint.setStrokeWidth(9);
drawPaint.setStyle(Paint.Style.STROKE);
drawPaint.setStrokeJoin(Paint.Join.ROUND);
drawPaint.setStrokeCap(Paint.Cap.ROUND);
canvasPaint = new Paint(Paint.DITHER_FLAG);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
drawCanvas = new Canvas(canvasBitmap);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
for (int i=0; i<paths.size(); i++) {
canvas.drawPath(paths.valueAt(i), drawPaint);
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
int index = event.getActionIndex();
int id = event.getPointerId(index);
Path path;
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
path = new Path();
path.moveTo(event.getX(index), event.getY(index));
paths.put(id, path);
break;
case MotionEvent.ACTION_MOVE:
for (int i=0; i<event.getPointerCount(); i++) {
id = event.getPointerId(i);
path = paths.get(id);
if (path != null) path.lineTo(event.getX(i), event.getY(i));
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
path = paths.get(id);
if (path != null) {
drawCanvas.drawPath(path, drawPaint);
paths.remove(id);
}
break;
default:
return false;
}
invalidate();
return true;
}
/**
* change path color here
*/
public void setPathColor(int color) {
drawPaint.setColor(color);
}
}
Answer
I take it that you are drawing this circle with your finger, and that when a lot of extra buttons are present, you notice that the lines you draw with your finger become "less smooth".
This is related to the app's screen refresh rate. When your app has to spend lots of time drawing all those extra buttons, it has fewer opportunities to get MotionEvents. With fewer MotionEvents, there are fewer points in your shape, and it takes longer line segments to connect them.
Suggested fix
The recommended approach is to stop those button views from being invalidated (an assumption on my part) every time onTouchEvent() gets called. From your code, I can't immediately see why they would be invalidated, but it may be that your DrawView underlies the buttons you are adding, thus whenever the DrawView is invalidate()-ed, the system must re-compose it with the buttons. You could move the DrawView so that it's by itself. Adding an opaque background to your button container(s) may help as well, b/c the system would have to do fewer alpha calculations.
You must have a lot of buttons... you may want to do some performance profiling to determine exactly what's taking so long.

How to add an ImageView to a custom view class in Android Studio?

Basically I've created a custom class which extends View and what it does currently is drawing a horizontal line where the screen is being touched until it's released. What I want to achieve is adding an ImageView in the background, behind the line so that line is drawn in the foreground. Here's the problem as I've got no clue how to add an ImageView to this view despite all the researches.
From my understanding the overriden onDraw function needs to: #1 clear the screen -> #2 draw the image on ImageView -> #3 draw the line on each iteration. I will have to later on implement dynamically image changing on said ImageView if this info helps somehow.
public class RateView extends View{
float touchY = (getHeight() / 2);
boolean isPressed = false;
Paint paint=new Paint();
public RateView(Context context, AttributeSet attrs) {
super(context);
this.setBackgroundColor(Color.parseColor("#da5f02"));
init(null);
}
private void init(AttributeSet attr){
paint.setColor(Color.GREEN);
paint.setStrokeWidth(10);
paint.setAntiAlias(true);
}
#Override
public void onDraw(Canvas canvas)
{
super.onDraw(canvas);
if (isPressed){
canvas.drawLine(5, touchY, (getWidth()-10), touchY,paint);
}
}
#Override
public boolean onTouchEvent(MotionEvent motionEvent){
switch (motionEvent.getAction()){
case MotionEvent.ACTION_DOWN:
isPressed = true;
break;
case MotionEvent.ACTION_MOVE:
touchY = motionEvent.getY();
break;
case MotionEvent.ACTION_UP:
isPressed = false;
break;
}
invalidate();
return true;
}}
This is my costum view class. My main class only extends AppCompatActivity and sets contentView to the above view. Thanks a lot for replys in advance!
EDIT: MainActivity
public class MainScreen extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View rateView = new RateView(this, null);
setContentView(rateView);
}
}
EDIT: MainActivity XML
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context=".MainScreen"
android:background="#da5f02">
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/Picture"
android:layout_alignParentStart="true"
android:layout_alignParentEnd="true"
android:background="#da5f02"
android:src="#drawable/monalisa"
android:adjustViewBounds="true"/>
</RelativeLayout>
If you will Custom view then you can add only one background for View so you should change your approach for above achievement.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context=".MainScreen"
android:background="#da5f02">
<com.yourpackage.RateView
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center_horizontal" />
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/Picture"
android:layout_alignParentStart="true"
android:layout_alignParentEnd="true"
android:background="#da5f02"
android:src="#drawable/monalisa"
android:adjustViewBounds="true"/>
</RelativeLayout>
Please look at this
public class MainScreen extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View rateView = new RateView(this, null);
setContentView(R.layout.activity_main);
}
}
public class RateView extends View
Add this view in Activity/Fragment
In activity_main put
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
>
<ImageView
android:layout_width="match_parent"
android:layout_height="5dp"
android:src="#drawable/image" />
<com.yourpackage.RateView
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center_horizontal" />
</LinearLayout>
add image here view can not add image.

Can't paint on surfaceview

I'm trying to use SurfaceView and want to paint on it, use code:
public class TestPaint extends SurfaceView {
public TestPaint(Context context) {
super(context);
setWillNotDraw(false);
setBackgroundColor(color.white);
}
#Override
protected void onDraw(Canvas canvas) {
Paint p = new Paint();
p.setColor(color.black);
canvas.drawText("test", 10, 10, p);
}
}
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TestPaint p=new TestPaint(this);
p.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
LinearLayout rl=(LinearLayout) findViewById(R.id.rltMain);
rl.addView(p);
}
}
The TestPaint display black background only. I try Why do I get it?
Using paint class better then that you have use frame layout and set text view or whatever u want.
Check this,
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<SurfaceView
android:id="#+id/surfaceView1"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</SurfaceView>
</LinearLayout>
<TextView
android:id="#+id/test"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top|right"
android:layout_marginRight="10dp"
android:layout_marginTop="10dp"
android:text="test"
android:background="#color/abc_search_url_text_normal"
android:textColor="#android:color/black"
android:textSize="20sp" />
</FrameLayout>

Android: add button and rectangle to layout

I'm new to Android. Here I draw a rectangle.
public class DrawView extends View
{
Paint paint = new Paint();
public DrawView(Context context)
{
super(context);
}
#Override
public void onDraw(Canvas canvas)
{
paint.setColor(Color.BLACK);
canvas.drawRect(30f, 30f, 80f, 80f, paint);
}
}
My XML code for adding button is :
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<Button
android:id="#+id/button1"
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="90dp"
android:layout_toRightOf="#+id/textView1"
android:text="Button" />
</RelativeLayout>
I have 2 doubts.
1)I want the rectangle in top of the app and the button in the bottom. How should I do it?
2) Later I want to change the color of rectangle. How should I get the rectangle to change the attributes?
1) Add the rectangle to your layout xml.-
<packageRouteToYourExtendedView.DrawView
android:id="#+id/rectangle"
android:layout_width="30dp"
android:layout_height="80dp"
android:layout_alignParentTop="true" />
2) Add a method to your extended view to change the color.-
public class DrawView extends View
{
Color color = Color.BLACK;
Paint paint = new Paint();
public DrawView(Context context)
{
super(context);
}
#Override
public void onDraw(Canvas canvas)
{
paint.setColor(color);
canvas.drawRect(30f, 30f, 80f, 80f, paint);
}
public changeColor(Color color) {
this.color = color;
invalidate();
}
}
And get the rectangle view to call your new method.-
DrawView rectangle = findViewById(R.id.rectangle);
rectangle.changeColor(Color.BLUE);

How to refresh a customized view in a layout

I just created a view for displaying PDF file
public class PDFGraphic extends View{
String mText;
float mLastX;
float mLastY;
public float mOffX;
public float mOffY;
Canvas mCan;
Bitmap mBi;
public PDFGraphic(Context context, AttributeSet attrs){
super(context,attrs);
setPageBitmap();
setBackgroundColor(Color.TRANSPARENT);
}
public void uiInvalidate() {
postInvalidate();
}
public void setPageBitmap() {
mBi = Bitmap.createBitmap(100, 100, Config.RGB_565);
mCan = new Canvas(mBi);
mCan.drawColor(Color.RED);
}
public void onDraw(Canvas canvas) {
Paint paint = new Paint();
canvas.drawBitmap(mBi, 0, 0, paint);
}
}
And this is my xml file(pdfview):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" android:orientation="vertical">
<RelativeLayout android:id="#+id/relativeLayout1" android:layout_width="match_parent" android:gravity="bottom|center" android:layout_height="wrap_content" android:minHeight="30px" android:visibility="visible">
<com.shawnprojectPDF.PDFGraphic android:id="#+id/pdfview1" android:layout_width="match_parent" android:layout_above="#+id/editText1" android:layout_alignParentTop="true" android:layout_height="match_parent"></com.shawnprojectPDF.PDFGraphic>
<ImageButton android:layout_height="wrap_content" android:layout_width="wrap_content" android:src="#drawable/leftarray" android:id="#+id/left" android:layout_alignParentBottom="true" android:layout_marginLeft="68px"></ImageButton>
<EditText android:id="#+id/editText1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="#+id/left" android:layout_alignParentBottom="true" android:gravity="center" android:width="100px" android:singleLine="true" android:maxLength="12"></EditText>
<ImageButton android:layout_height="wrap_content" android:layout_width="wrap_content" android:id="#+id/right" android:src="#drawable/rightarray" android:layout_toRightOf="#+id/editText1" android:layout_alignParentBottom="true"></ImageButton>
</RelativeLayout>
</LinearLayout>
In my main activity,if setContentView(R.Layout.pdfview), the view(PDFGraphic) will not be invalidated, if setContentView(New PDFGraphic(this)),it invalidates successfully.
How to refresh the view in the whole layout.
I don't see the problem. These are the results that I get with your code (next time, you do this part). With setContentView(R.layout.pdfview), this is the result:
With setContentView(new PDFGraphic(this, null) -- note that I used the two-arg constructor because you didn't define PDFGraphic(Context) -- this is the result:
In either case, your onDraw() is happening correctly.

Categories

Resources