Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Android portrait mode #111

Closed
donv opened this issue Apr 11, 2014 · 39 comments
Closed

Add support for Android portrait mode #111

donv opened this issue Apr 11, 2014 · 39 comments

Comments

@donv
Copy link

donv commented Apr 11, 2014

No description provided.

@srowen
Copy link
Contributor

srowen commented Apr 11, 2014

A bit of good news -- it already exists, although in the for-pay version.
https://play.google.com/store/apps/details?id=com.srowen.bs.android

It seems inevitable that this UI will be back-ported, like other features in that app. It's more feasible than it was.

It would be strange to have two quite different new UIs, so on the one hand you could say, no, nobody submit a new different portrait UI here. But then I'd be in the position of arguing against a valid enhancement just because I hadn't gotten around to back-porting the other UI.

But nobody has proposed any work on a portrait UI, so the issue hasn't been forced.

I think we could do two ways here. If someone suggested a minimal update to the current UI that made it work in portrait, I'd merge that with whatever internal changes are needed to really get it right and commit the result. It seems reasonable to entertain a new UI that is not the same as in BS+ but is as like the BS UI as possible.

@peitek
Copy link

peitek commented Jun 15, 2014

+1

@devjack
Copy link

devjack commented Aug 10, 2014

I'm looking at implementing support for the BarcodeScannerFragment to be used in portrait mode, similar size and dimensions to Facebook Messengers 'quick photo' feature. Problem being (I think) the framingRect passed into PlanarYUVLuminanceSource from CameraManager is of the wrong dimentions.

This goes a little beyond my android experience here w/ the camera manager so keen to hear thoughts on solving. From what I've been able to determine so far I suspect making the crop/framingrect more flexible will mean the fragment can be used in any dimension.

@srowen
Copy link
Contributor

srowen commented Aug 10, 2014

Yes, you have to request a preview size like "480x800" instead of "800x480" in portrait. You will also need to account for rotation, since the preview frame you get is still relative to the camera's orientation and may need to be 'rotated' to be read. And, the camera's orientation is not necessarily the same on all devices. And it's flipped for front cameras!

@youyi1314
Copy link

Nice,
I wish to have it support both portrait and landscape by using rotate the phone.
and also i like the barcodescanner+ layout, wish to has it update.

Thanks srowen for the source, I'm still learning android development skill.
Best Regards.

@dpolivy
Copy link

dpolivy commented Nov 12, 2014

I'd love to see this added, as well. Using this post as a guide, I'm able to get it working for the majority of users -- but I'm not sure it correctly accounts for base camera orientation. I have one user, who is using a custom ROM (Temasek, based on CM 11.0, and SlimKat) where the preview output is completely garbled.

Any tips on how/where to detect and compensate for camera orientation if it isn't defaulting to landscape? I'm happy to help contribute to this item if I can.

@ghost
Copy link

ghost commented Feb 10, 2015

+1

@fbreda
Copy link

fbreda commented Feb 10, 2015

+1

2015-02-10 15:06 GMT-02:00 WACMemphis notifications@github.com:

+1


Reply to this email directly or view it on GitHub
#111 (comment).

@srowen
Copy link
Contributor

srowen commented Feb 10, 2015

Hi all, +1 won't do anything, there's nobody taking feature requests, but I'll work with someone who wants to implement this to merge it with my implementation to make something best of both worlds.

@chepe263
Copy link

I was reading the help in the application. When my deviced changed orientation to landscape, the help went white. Is this the same issue?

@edy1
Copy link

edy1 commented Apr 4, 2015

+1

1 similar comment
@be1box
Copy link

be1box commented Apr 23, 2015

+1

@srowen
Copy link
Contributor

srowen commented Apr 23, 2015

@edy1 @mifa did you read my comment? +1 is just spam unless you are going to contribute code.

@fikisipi
Copy link

The method described here doesn't work on ZXing 3.2 because the viewport is a little bit stretched.

Any fix? I have rough idea of how SurfaceView, CameraConfigurationManager and CameraManager work, but I can't figure out why the preview math doesn't work.

(I have a 5 day deadline to finish QR scanning, and our app is portrait - I am basically f*cked)

@fikisipi
Copy link

I think this problem can be solved by using some code from this project

It's a lightweight library for zxing-core which works in portrait mode. I compared scanning QR codes, there are only two differences:

  • QRCodeReaderView has higher autofocus interval (easily modifiable)
  • QRCodeReaderView does not crop a specific zone, it scans the whole camera frame (easily modifiable)

@skzinzuwadia
Copy link

Hi,
https://github.com/dlazaro66/QRCodeReaderView
it did not support code 128

@schildbach
Copy link

Does QRCodeReaderView work only in portrait orientation? Unfortunately, then it would not solve my problem. My app works both in portrait and landscape, and the goal is using the scanner should not switch orientations.

@semieye
Copy link

semieye commented Nov 10, 2015

Hi guys,
try this project: https://github.com/dm77/barcodescanner
it works both in portrait and landscape.

@b1zantine
Copy link

Checkout this project too !!
https://github.com/SudarAbisheck/ZXing-Orient
It supports both portrait and Landscape mode too..

@KrasnayaPloshchad
Copy link
Contributor

The current version of Barcode Scanner can handle the initial orientation of camera when the app is opened, but cannot rotating it correctly when rotate the device in 180°, and the interface have no portrait mode when rotate the device in 90°.

@KrasnayaPloshchad
Copy link
Contributor

I think Open Camera also set an good example on screen mode and rotating behavior.

@liyzay
Copy link

liyzay commented Jun 16, 2016

@srowen I think I might find a way to support portrait mode.
Here is my steps:
1.I cloned the latest code from version 4.7.6
2.Removing "android:screenOrientation="sensorLandscape"" in AndroidManifest.xml
2.Removing lines from 172 to 176 in CaptureActivity.java to support both landscape and portrait
3.Changing portrait preview size by changing code in CameraConfigurationUtils.java
like this:

    double screenAspectRatio = (double) screenResolution.x / (double) screenResolution.y;
    //Consider portrait
    boolean isScreenPortrait = screenResolution.x < screenResolution.y;

    // Remove sizes that are unsuitable
    Iterator<Camera.Size> it = supportedPreviewSizes.iterator();
    while (it.hasNext()) {
        Camera.Size supportedPreviewSize = it.next();
        int realWidth = supportedPreviewSize.width;
        int realHeight = supportedPreviewSize.height;
        if (realWidth * realHeight < MIN_PREVIEW_PIXELS) {
            it.remove();
            continue;
        }

        boolean isCandidatePortrait = realWidth < realHeight;
        int maybeFlippedWidth = isScreenPortrait != isCandidatePortrait ? realHeight : realWidth;
        int maybeFlippedHeight = isScreenPortrait != isCandidatePortrait ? realWidth : realHeight;
        double aspectRatio = (double) maybeFlippedWidth / (double) maybeFlippedHeight;
        double distortion = Math.abs(aspectRatio - screenAspectRatio);
        if (distortion > MAX_ASPECT_DISTORTION) {
            it.remove();
            continue;
        }

        if (maybeFlippedWidth == screenResolution.x && maybeFlippedHeight == screenResolution.y) {
            Point exactPoint = new Point(realWidth, realHeight);
            Log.i(TAG, "Found preview size exactly matching screen size: " + exactPoint);
            return exactPoint;
        }
    }

4.Putting the "framingRectInPreview" rect center in the camera resolution screen by changing code in CameraManager.java like this:

    if (framingRectInPreview == null) {
        Rect framingRect = getFramingRect();
        if (framingRect == null) {
            return null;
        }
        Point cameraResolution = configManager.getCameraResolution();
        Point screenResolution = configManager.getScreenResolution();
        if (cameraResolution == null || screenResolution == null) {
            // Called early, before init even finished
            return null;
        }
        //Create a new rect which is same size as framingRect
        //And put the it center in the camera resolution screen
        Rect centerInCameraRect = new Rect() ;
        centerInCameraRect.left = (cameraResolution.x-framingRect.width())/2;
        centerInCameraRect.right = centerInCameraRect.left + framingRect.width() ;
        centerInCameraRect.top = (cameraResolution.y-framingRect.height())/2;
        centerInCameraRect.bottom = centerInCameraRect.top+framingRect.height() ;
        framingRectInPreview = centerInCameraRect ;
    }
    return framingRectInPreview;

I test those code with my phone and it works fine.

@srowen
Copy link
Contributor

srowen commented Jun 16, 2016

That sounds like a lot of the necessary change, though there needs to be some UI change too right? it doesn't really work on smaller screens in portrait otherwise.

@BS987
Copy link

BS987 commented Oct 7, 2016

@liyzay I tried your suggested code change on 4.7.7 version, screen is rotated fine and preview rectangle is also good. But it does not scan anything in portrait mode. Can you please suggest me what is wrong ? Did you checked it by scanning anything ?

@GuoJinyu
Copy link

GuoJinyu commented Nov 28, 2016

@srowen
I think the most important point to support for Android portrait mode is rotating the YUV preview frame data array, because the preview frame you get is only relative to the camera's orientation (always landscape at nearly all of Android phones) which has no relation to the screen's orientation.
So this is my steps to support portrait mode in version 4.7.7:

  1. Removing "android:screenOrientation="sensorLandscape" in AndroidManifest.xml
  2. Changing lines from 172 to 176 in CaptureActivity.java to support both landscape and portrait
if (prefs.getBoolean(PreferencesActivity.KEY_DISABLE_AUTO_ORIENTATION, true)) {
    setRequestedOrientation(getCurrentOrientation());
} else {
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
}
  1. Changing lines from 327 to 329 in CameraConfigurationUtils.java to get proper aspectRatio in accordence with screen orientation
boolean isScreenPortrait = screenResolution.x < screenResolution.y;
int maybeFlippedWidth = isScreenPortrait ? realHeight : realWidth;
int maybeFlippedHeight = isScreenPortrait ? realWidth : realHeight;
  1. Changing lines from 266 to 269 in CameraManager.java to get precise preview rectangle for camera.
if(screenResolution.x < screenResolution.y){
    // portrait
    rect.left = rect.left * cameraResolution.y / screenResolution.x;
    rect.right = rect.right * cameraResolution.y / screenResolution.x;
    rect.top = rect.top * cameraResolution.x / screenResolution.y;
    rect.bottom = rect.bottom * cameraResolution.x / screenResolution.y;
 } else {
    // landscape
    rect.left = rect.left * cameraResolution.x / screenResolution.x;
    rect.right = rect.right * cameraResolution.x / screenResolution.x;
    rect.top = rect.top * cameraResolution.y / screenResolution.y;
    rect.bottom = rect.bottom * cameraResolution.y / screenResolution.y;
}
  1. Changing lines from 47 to 48 in PreviewCallback.java to send proper width and height of preview frame
Point screenResolution = configManager.getScreenResolution();
Message message;
if (screenResolution.x < screenResolution.y){
    // portrait      
    message = thePreviewHandler.obtainMessage(previewMessage, cameraResolution.y,
          cameraResolution.x, data);
} else {
    // landscape
    message = thePreviewHandler.obtainMessage(previewMessage, cameraResolution.x,
    	   cameraResolution.y, data);
}
  1. Adding lines between 76 and 77 in DecodeHandler.java to rotate data when portrait
long start = System.currentTimeMillis();
if (width < height) {
    // portrait
    byte[] rotatedData = new byte[data.length];
    for (int x = 0; x < width; x++) {
        for (int y = 0; y < height; y++)
            rotatedData[y * width + width - x - 1] = data[y + x * height];
    }
    data = rotatedData;
}
Result rawResult = null;
  1. To support portrait mode perfectly, you should also do this follow my comment in this issue

Above-mentioned code modify has been tested on both 1D and 2D code and works good in my two Android phones with back camera.

BTW, I have published an Android scanner library by simplifying this Android project SimpleZXing

@ChinaBabyFace
Copy link

@BS987 Hi!I meet same problem like you.But QR-code can scan

@ChinaBabyFace
Copy link

@GuoJinyu 完美

@GuoJinyu
Copy link

@srowen sorry for my careless, I just modify my comment above and it can work properly.

@ghost
Copy link

ghost commented Feb 11, 2017

Honestly, just losing the text that shows up on the "bottom" (AKA sideways on the left side of the screen) would be enough of a fix for my (and probably most people's) purposes. It just makes the app look ridiculous and sloppily designed that the entire thing is portrait up until you open the QR reader and it insists on being landscape. Without the text, you wouldn't be able to tell it's gone into landscape. The instructions given by the text are beyond obvious anyway. It could just go away with no real impact on user experience.

@praveenshharma
Copy link

praveenshharma commented Jun 16, 2017

@GuoJinyu Perfect Solution but I think according to @srowen comment, this code won't work on smaller devices, as you can see the frame size in this hdpi device. Frame size is different as well as the scanning is not working properly. Do you have any update regarding this @srowen @GuoJinyu ?

img_20170617_130847

@GuoJinyu
Copy link

GuoJinyu commented Jun 20, 2017

@praveenshharma as for frame size, you can just add code like this in CameraManager

int width = findDesiredDimensionInRange(screenResolution.x, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH);
int height = findDesiredDimensionInRange(screenResolution.y, MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT);
if (width < height) {
    height = width;
}

@srowen
Copy link
Contributor

srowen commented Aug 23, 2017

I'm going to at long last declare that this won't happen in this project. However, I'm going to soon open source the 'plus' app anyway, which has this functionality.

@juqiu
Copy link

juqiu commented Sep 1, 2017

Just need to change lines in CameraManager.java to get precise preview rectangle can support portrait mode:

      if (screenResolution.y > screenResolution.x) { // portrait mode
            rect.left = framingRect.top * cameraResolution.x/ screenResolution.y;
            rect.top = (screenResolution.x-framingRect.right) * cameraResolution.y / screenResolution.x;
            rect.right = framingRect.bottom * cameraResolution.x / screenResolution.y;
            rect.bottom = (screenResolution.x-framingRect.left) * cameraResolution.y / screenResolution.x;
        } else {
            rect.left = rect.left * cameraResolution.x / screenResolution.x;
            rect.right = rect.right * cameraResolution.x / screenResolution.x;
            rect.top = rect.top * cameraResolution.y / screenResolution.y;
            rect.bottom = rect.bottom * cameraResolution.y / screenResolution.y;
        }

@biwoodfengs
Copy link

biwoodfengs commented Nov 3, 2017

Thanks @juqiu , My apps work in portrait mode, I found that it only decodes the center_horizontal parts of screen, then I make scan rectangle top of screen, the decode area has a right shifts. juqiu's resolution make me ajust the decode area in portrait mode works properly.

@maverick74
Copy link

@srowen where can we get updated about the opensourcing of the "plus" version, when it happens???

I ask this because i try to use opensource apps everywhere i can, so i'm interested in this!

Thanks :)

@srowen
Copy link
Contributor

srowen commented Dec 18, 2017

@maverick74
Copy link

@srowen I was hopping you would have a blog or something that would have more "up-to-date" news :)

Will keep an eye on PlayStore, then!

Happy Holidays

Thanks

@agbaraka
Copy link

agbaraka commented Mar 5, 2018

As of zxing library:2.2.0

AndroidManifest.xml

<activity
    android:name="com.journeyapps.barcodescanner.CaptureActivity"
    android:screenOrientation="fullSensor"
    tools:replace="screenOrientation" />

Set additional property at call to scanner :

IntentIntegrator integrator = new IntentIntegrator(this);
//set orientation locked to false
integrator.setOrientationLocked(false);

@yangyiRunning
Copy link

yangyiRunning commented Aug 13, 2018

@GuoJinyu

DecodeHandler类中的rotatedData[y * width + width - x - 1] = data[y + x * height];这一行,会报错java.lang.OutOfMemoryError: Failed to allocate a 8294412 byte allocation with 1375816 free bytes and 1343KB until OOM, 有什么解决的办法么?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests