nisrulz / qreader

:white_square_button: [Android Library] Read QR codes using google's mobile vision api, but without the hassle
http://nisrulz.github.io/qreader
Apache License 2.0
371 stars 108 forks source link

Camera is stretched #58

Closed morra850 closed 3 years ago

morra850 commented 6 years ago

Hello, I have created a layout on android with a simple menu of 50dp and under a "surfaceview" where I used the library of qr reader to read the qr code, only that the camera is stretched, I also tried to enter 50 dp margin to surface view to keep the spaces, but nothing has changed, how can I solve this problem?

I used version 2.1.2 of the library

Preview:

0f87eb24-820b-480d-ab1e-b83c38809082

nisrulz commented 6 years ago

Have you checked out the sample app? Does the issue occur in the sample app too?

Can you create a simple implementation reproducing the issue for me to debug?

Thank you

morra850 commented 6 years ago

My code is the same as the demo, I enter the code below:

`package eu.followine.followine;

import android.Manifest; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.content.res.Resources; import android.graphics.Point; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.support.design.widget.NavigationView; import android.support.v4.app.ActivityCompat; import android.support.v4.widget.DrawerLayout; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.util.TypedValue; import android.view.Display; import android.view.Gravity; import android.view.MenuItem; import android.view.SurfaceView; import android.view.View; import android.widget.ImageButton;

import com.loopj.android.http.AsyncHttpClient; import com.loopj.android.http.AsyncHttpResponseHandler; import com.loopj.android.http.RequestParams;

import org.json.JSONException; import org.json.JSONObject;

import java.io.IOException; import java.io.UnsupportedEncodingException;

import cz.msebera.android.httpclient.Header; import github.nisrulz.qreader.QRDataListener; import github.nisrulz.qreader.QREader;

public class Main extends AppCompatActivity { private SurfaceView mySurfaceView; private QREader qrEader;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    final DrawerLayout mDrawerLayout = findViewById(R.id.drawer_layout);
    mySurfaceView = (SurfaceView) findViewById(R.id.camera_view);
    qrEader = new QREader.Builder(this, mySurfaceView, new QRDataListener() {
        @Override
        public void onDetected(final String data) {

        }
    }).facing(QREader.BACK_CAM)
            .enableAutofocus(true)
            .height(mySurfaceView.getHeight())
            .width(mySurfaceView.getWidth())
            .build();

}

@Override
protected void onStart() {
    super.onStart();
    qrEader.start();
}

@Override
protected void onResume() {
    super.onResume();

    qrEader.initAndStart(mySurfaceView);
    isCheck = 0;
}

@Override
protected void onPause() {
    super.onPause();

    qrEader.releaseAndCleanup();
}

} `

And this is the xml:

`<?xml version="1.0" encoding="utf-8"?> <android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/drawer_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true">

<FrameLayout
    android:id="@+id/content_frame"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:theme="@style/ThemeOverlay.AppCompat.ActionBar" />

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <include
            android:id="@+id/menu"
            layout="@layout/menu"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentStart="true"
            android:layout_alignParentTop="true" />

        <SurfaceView
            android:id="@+id/camera_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_below="@id/menu"
            android:layout_weight="1" />

    </RelativeLayout>
</FrameLayout>

<android.support.design.widget.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:menu="@menu/drawer_view"/>

</android.support.v4.widget.DrawerLayout>`

PS: Menu height is 50dp

morra850 commented 6 years ago

Any news? please help me

johan-steffens commented 6 years ago

What happens if you remove android:layout_weight="1" from your SurfaceView?

From what I can tell there's no use for it and it might do some weird measurement things behind the scenes.

Also you have a duplicate declaration of your android XML namespace. Maybe remove the declaration from your RelativeLayout and see if that helps.

westnordost commented 6 years ago

There are several issues at play here:

  1. The QREader.Builder requires the width and height of the size to be defined at the time the QREader is built. QREader assumes (=requires) that QREader.initAndStart(SurfaceView surfaceView) is called before the mentioned final size is calculated, so for example on onResume which makes it impossible to supply the correct size calculated from a ViewTreeObserver.OnGlobalLayoutListener to the builder
  2. Because of the above (the QREader must be created in onCreate or latest in onResume), the camera permission must already been granted in the activity / fragment in which the class is used. (The sample app "solves" this by restarting the activity when. Obviously, this solution is not applicable for everyone)
  3. The size as set in the builder is just the requested preview size which means that there is no guarantee that the camera shoves bitmaps onto the SurfaceView in exactly that size. Due to the nature how a SurfaceView works, IIRC, the source bitmap is stretched onto the view. To solve this, one has to manually recalculate the bounds of the bitmap to simulate/reimplement a ScaleType.CENTER_CROP as seen for ImageViews.
reshadf commented 6 years ago

We have users in our app where the camera is black. ( on some devices ) we haven't been able to reproduce this issue, however, I think it might have to do something with the SurfaceView not being able to preview the camera on these devices. The reason might be connected to the stretching where some devices just preview a black screen instead of a stretched view. is this possible?

@westnordost do you have some example of how to implement your solution to fix the stretching?

westnordost commented 6 years ago

No, I do not have an example (it is not open source), but I can roughly lay it out for you: Let's say the camera preview is for some reason a square, while the surface view is a 1:2 (portrait) rectangle. One trick to make the camera picture appear non-skewed is to make the surface view itself have the same aspect ratio as the camera picture (in this case, a square) by modifying its margins (and ensuring the parent view clips to bounds, which is the default though anyway).

To achieve something like CENTER_CROP, set negative margins so that width - horizontal margins / (height - vertical margins) = desired aspect ratio, which is 1 in this case. To achieve something like CENTER_INSIDE, use positive margins.

For the example of the square and the portrait, you would set a negative horizontal margin for CENTER_CROP or a positive vertical margin for CENTER_INSIDE.

nisrulz commented 3 years ago

Closing as issue is outdated. Please open a new issue if the issue still persists.