47

I'm trying to develop my own camera activity, but I have a problem that I'm not unable to solve...

What I want, is something very similiar to instagram photo frame, and this is what I get:

My image

When I should get something like this:

Instagram image

and...

My second image

when I should get something like:

Instagram 2

I think I'm maanaging the SurfaceView and Camera preview well, only using

Camera.Parameters parameters = camera.getParameters();
camera.setDisplayOrientation(90);

and Custom SurfaceView:

public class SquaredSurfaceView extends SurfaceView {

private int width;
private int height;

public SquaredSurfaceView(Context context) {
    super(context);
}

public SquaredSurfaceView(Context context, AttributeSet attrs) {
    super(context, attrs);
}

public SquaredSurfaceView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    width = MeasureSpec.getSize(widthMeasureSpec);
    height = width;
    setMeasuredDimension(width, width);
}

public int getViewWidth() {
    return width;
}

public int getViewHeight() {
    return height;
}

}

What I'm doing wrong?? :-(

cesards
  • 14,087
  • 11
  • 63
  • 63
  • 1
    Well firstly, they look similar except your CameraPreview isn't centered. Also, you should check to make sure the preview size you're looking for is actually supported by the camera: Camera.Parameters params = mCamera.getParameters(); sizes = params.getSupportedPreviewSizes(); Then just loop through the sizes to find the supported size you're looking for (IE. 1:1, if it's even available). For it to actually show up as a 1:1 ratio, though, you may need to clip part of the view – Cruceo Jun 20 '12 at 14:48
  • I've tried yet: mSupportedPreviewSizes = parameters.getSupportedPreviewSizes(); Camera.Size size = mSupportedPreviewSizes.get(2); if (size != null /* && pictureSize != null */) { parameters.setPreviewSize(size.width, size.height); .... } – cesards Jun 20 '12 at 16:59
  • But you're not checking the aspect ratio; you're just setting it to one of the available preview sizes. To get the right ration you're asking for, you'll have to compare the width/height – Cruceo Jun 20 '12 at 17:15
  • I've already done it, but it didn't work... – cesards Jun 28 '12 at 11:44
  • @Guardanis, but there is no 1:1 preview size (well there isn't on my phone here). – Brad Moore Feb 07 '14 at 05:34
  • @BradMoore I don't expect there to -ever- be an actual 1:1 ratio. What you're going to have to do is scale the image (while maintaining aspect ratio) until all dimensions of the image are greater than or equal to their respective boundaries. Once the image is scaled, you can crop it to your desired bounds – Cruceo Feb 14 '14 at 20:52
  • @Guardanis, yeah I got the smallest of the surfaceview sizes and scaled it maintaining aspect ratio to fit the width of my device. Is in a framelayout so hopefully I can just overlay a linearlayout/view or something over the bottom, then just crop the image when I actually take the photo. – Brad Moore Feb 15 '14 at 22:47
  • @BradMoore Have you tried pseudo: That would allow the Linear to float above the frame – Cruceo Feb 17 '14 at 17:58
  • sir please provide the source code – Ashok Oct 27 '14 at 13:43
  • sir please provide the source code ? thanks in advance – Ersin Gülbahar Nov 26 '14 at 12:26
  • @m3n0R : Hi did you got any solution ? i am also stuck there. I am trying found solution last many days but still did't get something. If you have complete then please share. Thanks in advance. – Teraiya Mayur Jun 01 '15 at 06:54
  • 1
    @m3n0R : did you get any solution i am also stuck there ? – Teraiya Mayur Jul 06 '15 at 05:56
  • It was almost 4 years ago... Try to search for new Camera API projects. It will help you :-) – cesards Jul 07 '15 at 09:00
  • Any new solutions to this, I am also looking for a solution here, and does it work the same for videos... or anyone have links to connect to here for more recent questions. – Lion789 Jul 26 '15 at 19:24

6 Answers6

19

As said before you need to find the correct preview size (the one with aspect ratio 1:1) and probably you have to use FrameLayout for the SurfacePreview. It seems that you have and aspect ratio problem maybe you have the right preview size but you are placing it in an incorrect layout.

Another solution might be (just like Instagram does) to make your camera at full size and then hide some areas of the layout just to make it look like a square. Then by software you would have to cut the image to make it a real square.

Hope this helps you

Philipp Kyeck
  • 16,652
  • 15
  • 72
  • 105
xramos
  • 226
  • 3
  • 9
  • 2
    @xramos how can i do that thing that instagram did? do you have any reference or pointers? please help me :) thank you. – CENT1PEDE Jan 14 '14 at 11:08
  • I am interested in how IG do this also. – Brad Moore Feb 07 '14 at 05:23
  • 1
    i think if allready explained it. i don't know if instagram actually does so but it seems so. get you camera preview size that works for your device and then just put some black layouts on top of your camera frame layout to make your visible camera squared. you will need to do some calculations later when you take a picture. But again, i'm not sure if they're actually doing so – xramos Feb 07 '14 at 10:44
  • @xramos : Hie i had implement full camera as you mention but can't crop proper for all devices. There are also different camera resolution for all devices . Can you help me? waiting for your feedback. – Teraiya Mayur Jul 06 '15 at 05:51
7

The solution that works for me is the 2nd Answer, but because we need to rotate the camera 90º is necessary to switch the WIDTH with the HEIGTH, something like this...

   camera.setDisplayOrientation(90);
   Camera.Parameters params= camera.getParameters();
   surfaceView.getLayoutParams().width=params.getPreviewSize().height;
   surfaceView.getLayoutParams().height=params.getPreviewSize().width;

Hope this solution helps!! :D

Ycastan
  • 79
  • 1
  • 3
  • This caused an exception for me. – The Hungry Androider Jul 29 '15 at 14:05
  • Thanks for the answer.Can you please tell me why it working like that? – VikasGoyal Apr 26 '16 at 09:33
  • 1
    It solve my problem on nexus 5x but I am still getting problem with moto g2 is that behaving different for different version of devices or their is some other scenario for it. – VikasGoyal Apr 26 '16 at 09:34
  • I have been looking at this problem for half a day; the solution proposed here: http://stackoverflow.com/questions/19577299/android-camera-preview-stretched, kind of work but it can downgrade the performance (hence not so good solution). I've tried your solution that seemed really easy compare to the one in the other doc, I put some `Log.d(..)` to check size of height and width before and after your code and nothing changed. – nyluje Oct 26 '16 at 16:26
2

my solution is more like building a square mask and then to place it over the preview surface.

You will need 3 things mainly, first a square frame component. I've made a custom component:

package com.example.squaredviewer;

import android.content.Context;
import android.util.AttributeSet;
import android.view.Display;
import android.view.WindowManager;
import android.widget.RelativeLayout;

/**
* Created by yadirhb on 14-08-2015.
*/
public class SquaredFrame extends RelativeLayout{
    public SquaredFrame(Context context, AttributeSet attrs) {
         super(context, attrs);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int size = Math.min(getMeasuredWidth(), getMeasuredHeight());
        setMeasuredDimension(size, size);
    }
}

Depending of the Android API version for the which you're developing, you will maybe need to add another constructor overload. For Kitkat this is just fine.

The second step is to build the layout:

<?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"
android:orientation="horizontal"
android:visibility="visible">

<RelativeLayout
    android:id="@+id/camera_preview"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentLeft="false"
    android:layout_alignParentTop="false"
    android:layout_centerInParent="true"
    android:background="#ffffff">

</RelativeLayout>

<LinearLayout
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:background="#131008">

    </LinearLayout>

    <com.example.squaredviewer.SquaredFrame
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_centerInParent="true"></com.example.squaredviewer.SquaredFrame>

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:background="#131008" />
</LinearLayout>
</RelativeLayout>

Notice that the RelativeLayout "camera_preview" is the one used to render the preview, it is centered and has a LinearLayout which contains the squared component. This is actually the "mask" and it covers the camera preview. Notice also that except the SquaredFrame, which is transparent, the others two are background coloured with black.

Now the surface view, for the camera preview in which the surface is sized acording the aspect ratio.

public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {

    private final String TAG = "PIC-FRAME";

    private SurfaceHolder mHolder;
    private Camera mCamera;
    private Display display;

    public CameraPreview(Activity context, Camera camera) {
        super(context);
        mCamera = camera;
        display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();

        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        mHolder = getHolder();
        mHolder.addCallback(this);
        // deprecated setting, but required on Android versions prior to 3.0
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

        setKeepScreenOn(true);
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        // empty. Take care of releasing the Camera preview in your activity.
        this.getHolder().removeCallback(this);
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        // If your preview can change or rotate, take care of those events here.
        // Make sure to stop the preview before resizing or reformatting it.

        if (mHolder.getSurface() == null) {
            // preview surface does not exist
            return;
        }

        try {
            // stop preview before making changes
            mCamera.stopPreview();
            // set preview size and make any resize, rotate or
            // reformatting changes here
            // Now that the size is known, set up the camera parameters and begin
            // the preview.
            Camera.Parameters parameters = mCamera.getParameters();
            // You need to choose the most appropriate previewSize for your app
            Camera.Size previewSize = parametes.getSupportedPreviewSizes().get(0);
            parameters.setPreviewSize(previewSize.width, previewSize.height);


             // start preview with new settings
             mCamera.setParameters(parameters);

             // Set the holder size based on the aspect ratio
             int size = Math.min(display.getWidth(), display.getHeight());
             double ratio = (double) previewSize.width / previewSize.height;

             mHolder.setFixedSize((int)(size * ratio), size);
             mCamera.setPreviewDisplay(mHolder);
             mCamera.startPreview();

         } catch (Exception e) {
             Log.d(TAG, "Error starting camera preview: " + e.getMessage());
         }
      }
   }
}

Now everything must be tied in the activity class

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_picture_taker);

    mDecorView = getWindow().getDecorView();

    //mCamera = a camera instance;

    // Create our Preview view and set it as the content of our activity.
    mPreview = new CameraPreview(this, mCamera);

    //Layout where camera preview is shown.
    RelativeLayout preview = (RelativeLayout) findViewById(R.id.camera_preview);
    //FrameLayout stack controllers inside and superpose them.
    preview.addView(mPreview, 0);

    // TODO
}

A little long, but I hope it be helpful for more than one. :-)

YadirHB
  • 139
  • 11
2

I had the same problem with a square view - resolved it simply by setting the SurfaceView's camera size to the size of the view where I wanted to draw it. No complicated calculations and it works for me. See my response here for the whole method: https://stackoverflow.com/a/39430615/5181489

public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        ...
        params.setPreviewSize(viewParams.height, viewParams.width);
        camera.setParameters(params);
Community
  • 1
  • 1
Martin Šuráb
  • 167
  • 2
  • 5
-1

You can use this to get pictureSize:

public static void initialCameraPictureSize(Context context, android.hardware.Camera.Parameters parameters) {

    List list = parameters.getSupportedPictureSizes();
    if(list != null) {
        android.hardware.Camera.Size size = null;
        Iterator iterator = list.iterator();
        do {
            if(!iterator.hasNext())
                break;
            android.hardware.Camera.Size size1 = (android.hardware.Camera.Size)iterator.next();
            if(Math.abs(3F * ((float)size1.width / 4F) - (float)size1.height) < 0.1F * (float)size1.width && (size == null || size1.height > size.height && size1.width < 3000))
                size = size1;
        } while(true);
        if(size != null)
            parameters.setPictureSize(size.width, size.height);
        else
            Log.e("CameraSettings", "No supported picture size found");
    }
}
ubuntudroid
  • 3,068
  • 5
  • 32
  • 54
shailesh
  • 1,763
  • 2
  • 16
  • 25
-1

It's so hard. Not easily.

First thing : You define 2 black Linear Layout to get the UI as you posted.

Second thing : you need cut the picture from full picture to square picture.

How to cut, you need use scaleBitmap method.

Or you want real Custom Camera? Can check in here

Huy Tower
  • 7,162
  • 13
  • 49
  • 81
  • 1
    An answer typically contains a bit more details like code or more detailed explanations. Adding that would definitely make this more useful. – Trilarion Jan 31 '16 at 22:04