/* Copyright (C) 2014,2015 Philipp Lenk
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package de.hu_berlin.informatik.spws2014.mapever.camera;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.hardware.Camera;
import android.hardware.Camera.CameraInfo;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.Size;
import android.media.ExifInterface;
import android.util.AttributeSet;
import android.view.OrientationEventListener;
import org.opencv.android.JavaCameraView;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;
@SuppressWarnings("deprecation")
public class CornerDetectionView extends JavaCameraView implements PictureCallback
{
interface PictureCallback
{
void onPictureTaken();
}
public CornerDetectionView(Context context, AttributeSet attrs)
{
super(context, attrs);
orientation_listener = new OrientationEventListener(context)
{
@Override
public void onOrientationChanged(int orientation)
{
device_orientation=(orientation + 45) / 90 * 90;
}
};
}
public void startMonitoringOrientation()
{
orientation_listener.enable();
}
public void stopMonitoringOrientation()
{
orientation_listener.disable();
}
public List<Size> get_preview_resolutions()
{
return mCamera == null ?
new ArrayList<Size>() :
mCamera.getParameters().getSupportedPreviewSizes();
}
public void set_preview_resolution(Size new_resolution)
{
disconnectCamera();
mMaxHeight = new_resolution.height;
mMaxWidth = new_resolution.width;
connectCamera(getWidth(), getHeight());
}
public Size get_preview_resolution()
{
return mCamera.getParameters().getPreviewSize();
}
public List<Size> get_picture_resolutions()
{
return mCamera == null ?
new ArrayList<Size>() :
mCamera.getParameters().getSupportedPictureSizes();
}
public List<String> get_flash_modes()
{
return mCamera == null ?
null :
mCamera.getParameters().getSupportedFlashModes();
}
public void set_flash_mode(String mode)
{
Parameters params = mCamera.getParameters();
params.setFlashMode(mode);
mCamera.setParameters(params);
}
public void set_picture_resolution(Size new_resolution)
{
Parameters params = mCamera.getParameters();
params.setPictureSize(new_resolution.width, new_resolution.height);
mCamera.setParameters(params);
}
public Size get_picture_resolution()
{
return mCamera.getParameters().getPictureSize();
}
public void take_picture(String filename, PictureCallback callback)
{
picture_filename = filename;
picture_callback = callback;
mCamera.setPreviewCallback(null);
updateOrientation();
final CornerDetectionView this_ref=this;
mCamera.autoFocus(new Camera.AutoFocusCallback()
{
@Override
public void onAutoFocus(boolean success, Camera cam)
{
cam.takePicture(null, null, null, this_ref);
}
});
}
@Override
public void onPictureTaken(byte[] data, Camera camera)
{
mCamera.startPreview();
mCamera.setPreviewCallback(this);
try
{
FileOutputStream fos = new FileOutputStream(picture_filename);
fos.write(data);
fos.close();
}
catch (java.io.IOException e)
{
e.printStackTrace();
}
correctImage();
picture_callback.onPictureTaken();
}
private void updateOrientation()
{
if(mCamera == null || device_orientation == OrientationEventListener.ORIENTATION_UNKNOWN)
return;
CameraInfo info = new CameraInfo();
Camera.getCameraInfo(getCameraId(),info);
int rotation = 0;
if(info.facing == CameraInfo.CAMERA_FACING_FRONT)
{
rotation = (info.orientation - device_orientation +360) % 360;
}
else
{
rotation = (info.orientation + device_orientation) % 360;
}
Parameters params = mCamera.getParameters();
params.setRotation(rotation);
mCamera.setParameters(params);
}
//needed because some devices save rotation as exif information only, but dont rotate the pixels
//that wouldnt be a problem if bitmapfactory would actually use that exif information, but well...
private void correctImage()
{
try
{
ExifInterface exif = new ExifInterface(picture_filename);
int rotation_value = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION,ExifInterface.ORIENTATION_NORMAL);
switch(rotation_value)
{
case ExifInterface.ORIENTATION_ROTATE_90:
rotateImage(90);
break;
case ExifInterface.ORIENTATION_ROTATE_180:
rotateImage(180);
break;
case ExifInterface.ORIENTATION_ROTATE_270:
rotateImage(270);
break;
default:
break;
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
//pretty ugly and uses way too much memory, better suggestions more than welcome...
private void rotateImage(int degree)
{
try
{
Bitmap btm = BitmapFactory.decodeFile(picture_filename);
Matrix mat = new Matrix();
mat.postRotate(degree);
btm = Bitmap.createBitmap(btm, 0, 0, btm.getWidth(), btm.getHeight(), mat, true);
FileOutputStream fos = new FileOutputStream(picture_filename);
btm.compress(Bitmap.CompressFormat.JPEG, 100, fos);
fos.close();
}
catch(Exception e)
{
e.printStackTrace();
}
}
//needed because opencv opens a camera and does not remember which...
//and android is not wise enough to tell me...
//luckily i happen to know we use the first backfacing camera and if none of those is found we use the first frontfacing one
//this is incredibly ugly so, therefore if anyone has a better idea feel free to use it ;_;
private int getCameraId()
{
CameraInfo info = new CameraInfo();
for(int idx=0;idx<Camera.getNumberOfCameras();++idx)
{
Camera.getCameraInfo(idx,info);
if(info.facing==CameraInfo.CAMERA_FACING_BACK)
return idx;
}
return 0;
}
private String picture_filename;
private PictureCallback picture_callback;
private OrientationEventListener orientation_listener;
private int device_orientation;
}