I know lot of question has been asked on this. i have tried some of them. But nothing is working for me. Here is how i am creating my preview
TextureView.SurfaceTextureListener listener = new TextureView.SurfaceTextureListener() {
#Override
public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) {
fetchCameraData();
prepareSurface();
prepareCameraDevice(cameraId);
}
#Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int i, int i1) {
}
#Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture)
{
return true;
}
#Override
public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
}
};
private void prepareCamera() {
previewView = (AutoFitTextureView) findViewById(R.id.textureview);
previewView.setSurfaceTextureListener(listener);
}
private void fetchCameraData() {
cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try {
for (String cameraID : cameraManager.getCameraIdList()) {
cameraCharacteristics = cameraManager.getCameraCharacteristics(cameraID);
if (cameraCharacteristics.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_FRONT) {
continue;
}
cameraId = cameraID;
StreamConfigurationMap streamConfigs = cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
previewSize = Collections.max(
Arrays.asList(streamConfigs.getOutputSizes(ImageFormat.JPEG)),
new CompareSizesByArea());
break;
}
} catch (CameraAccessException e) {
e.printStackTrace();
Toast.makeText(this, "Unable to fetch camera data", Toast.LENGTH_SHORT).show();
}
}
private void prepareSurface() {
SurfaceTexture texture = previewView.getSurfaceTexture();
textureSurface = new Surface(texture);
jpegReader = ImageReader.newInstance(previewSize.getWidth(), previewSize.getHeight(), ImageFormat.JPEG, 1);
jpegSurface = jpegReader.getSurface();
jpegReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
#Override
public void onImageAvailable(ImageReader imageReader) {
Image image = imageReader.acquireLatestImage();
ByteBuffer byteBuffer = image.getPlanes()[0].getBuffer();
byte jpegBytes[] = new byte[byteBuffer.remaining()];
byteBuffer.get(jpegBytes);
Bitmap imageBitmap = BitmapFactory.decodeByteArray(jpegBytes, 0, jpegBytes.length);
capturedImage = imageBitmap;
decodeBase64Image(getBase64Image(imageBitmap));
image.close();
}
}, null);
}
private void prepareCameraDevice(String cameraId) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
try {
cameraManager.openCamera(cameraId, new CameraDevice.StateCallback() {
#Override
public void onOpened(#NonNull CameraDevice cameraDevice) {
mCameraDevice = cameraDevice;
prepareCaptureSession();
}
#Override
public void onDisconnected(#NonNull CameraDevice cameraDevice) {
}
#Override
public void onError(#NonNull CameraDevice cameraDevice, int i) {
}
}, null);
} catch (CameraAccessException e) {
e.printStackTrace();
Toast.makeText(this, "Unable to user Camera", Toast.LENGTH_SHORT).show();
}
} else {
requestPermission();
}
}
private void prepareCaptureSession() {
List<Surface> surfaceList = Arrays.asList(textureSurface, jpegSurface);
try {
mCameraDevice.createCaptureSession(surfaceList, new CameraCaptureSession.StateCallback() {
#Override
public void onConfigured(#NonNull CameraCaptureSession cameraCaptureSession) {
session = cameraCaptureSession;
startCamera();
}
#Override
public void onConfigureFailed(#NonNull CameraCaptureSession cameraCaptureSession) {
}
}, null);
} catch (CameraAccessException e) {
e.printStackTrace();
Toast.makeText(this, "Unable to create session", Toast.LENGTH_SHORT).show();
}
}
private void startCamera() {
try {
requestPreview = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
requestPreview.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
requestPreview.addTarget(textureSurface);
session.setRepeatingRequest(requestPreview.build(), null, null);
} catch (CameraAccessException e) {
Toast.makeText(this, "Unable to create preview", Toast.LENGTH_SHORT).show();
}
}
My AutoFitTextureView class is as below
public class AutoFitTextureView extends TextureView {
private int mRatioWidth = 0;
private int mRatioHeight = 0;
public AutoFitTextureView(Context context) {
this(context, null);
}
public AutoFitTextureView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public AutoFitTextureView(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
}
/**
* Sets the aspect ratio for this view. The size of the view will be measured based on the ratio
* calculated from the parameters. Note that the actual sizes of parameters don't matter, that
* is, calling setAspectRatio(2, 3) and setAspectRatio(4, 6) make the same result.
*
* #param width Relative horizontal size
* #param height Relative vertical size
*/
public void setAspectRatio(int width, int height) {
if (width < 0 || height < 0) {
throw new IllegalArgumentException("Size cannot be negative.");
}
if (mRatioWidth == width && mRatioHeight == height) {
return;
}
mRatioWidth = width;
mRatioHeight = height;
requestLayout();
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
if (0 == mRatioWidth || 0 == mRatioHeight) {
setMeasuredDimension(width, height);
} else {
if (width < height * mRatioWidth / mRatioHeight) {
setMeasuredDimension(width, width * mRatioHeight / mRatioWidth);
} else {
setMeasuredDimension(height * mRatioWidth / mRatioHeight, height);
}
}
}
}
And here is my xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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="in.thoughtsmith.miinterface.MainActivity">
<Button
android:id="#+id/scanButton"
android:layout_width="70dp"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginEnd="10dp"
android:layout_marginTop="10dp"
android:layout_weight="1"
android:alpha="0.50"
android:background="#drawable/button_shape"
android:text="Scan"
android:textColor="#color/white" />
<in.thoughtsmith.miinterface.AutoFitTextureView
android:id="#+id/textureview"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<ImageView
android:id="#+id/captureImage"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:visibility="gone" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:orientation="horizontal"
android:weightSum="2">
<Button
android:id="#+id/buyButton"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_marginBottom="10dp"
android:layout_marginEnd="10dp"
android:layout_marginStart="5dp"
android:layout_weight="1"
android:alpha="0.5"
android:background="#drawable/button_shape"
android:text="Buy"
android:textColor="#color/white" />
<Button
android:id="#+id/accessoriesButton"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_marginBottom="10dp"
android:layout_marginEnd="5dp"
android:layout_marginStart="10dp"
android:layout_weight="1"
android:alpha="0.5"
android:background="#drawable/button_shape"
android:text="Accessories"
android:textColor="#color/white" />
</LinearLayout>
</RelativeLayout>
Above code give me distorted preview image in some device. It give me distorted preview display on OnePlus 3T device.
Change the layout_width and layout_height to be "wrap_content", not "match_parent" for your AutoFitTextureView.
"match_parent" doesn't let the View override the size, which you need here.
Related
I have CustomView with 2 RelativeLayouts. There are RecyclerViews in each RelativeLayout. When I add new element to RecyclerView it doesn`t change height.
If I change screen orientation then android measures it well. So my question is how to programmatically tell android that he needs remeasure both childs and parent elements.
requestlayout() and invalidate() doesn`t work
CustomView:
public class ExpandableView extends LinearLayout {
private Settings mSettings ;
private int mExpandState;
private ValueAnimator mExpandAnimator;
private ValueAnimator mParentAnimator;
private AnimatorSet mExpandScrollAnimatorSet;
private int mExpandedViewHeight;
private boolean mIsInit = true;
private int defaultHeight;
private boolean isAllowedExpand = false;
private ScrolledParent mScrolledParent;
private OnExpandListener mOnExpandListener;
public ExpandableView(Context context) {
super(context);
init(null);
}
public ExpandableView(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
public ExpandableView(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
private void init(AttributeSet attrs) {
Log.w("tag", "init");
setOrientation(VERTICAL);
this.setClipChildren(false);
this.setClipToPadding(false);
mExpandState = ExpandState.PRE_INIT;
mSettings = new Settings();
if(attrs!=null) {
TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.ExpandableView);
mSettings.expandDuration = typedArray.getInt(R.styleable.ExpandableView_expDuration, Settings.EXPAND_DURATION);
mSettings.expandWithParentScroll = typedArray.getBoolean(R.styleable.ExpandableView_expWithParentScroll,false);
mSettings.expandScrollTogether = typedArray.getBoolean(R.styleable.ExpandableView_expExpandScrollTogether,true);
typedArray.recycle();
}
}
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
Log.w("tag", "onMeasure");
Log.w("tag", "widthMeasureSpec - " + widthMeasureSpec);
Log.w("tag", "heightMeasureSpec - " + heightMeasureSpec);
int childCount = getChildCount();
if(childCount!=2) {
throw new IllegalStateException("ExpandableLayout must has two child view !");
}
if(mIsInit) {
((MarginLayoutParams)getChildAt(0).getLayoutParams()).bottomMargin=0;
MarginLayoutParams marginLayoutParams = ((MarginLayoutParams)getChildAt(1).getLayoutParams());
marginLayoutParams.bottomMargin=0;
marginLayoutParams.topMargin=0;
marginLayoutParams.height = 0;
mExpandedViewHeight = getChildAt(1).getMeasuredHeight();
defaultHeight = mExpandedViewHeight;
mIsInit =false;
mExpandState = ExpandState.CLOSED;
View view = getChildAt(0);
if (view != null){
view.setOnClickListener(v -> toggle());
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
Log.w("tag", "onSizeChanged");
if(mSettings.expandWithParentScroll) {
mScrolledParent = Utils.getScrolledParent(this);
}
}
private int getParentScrollDistance () {
int distance = 0;
Log.w("tag", "getParentScrollDistance");
if(mScrolledParent == null) {
return distance;
}
distance = (int) (getY() + getMeasuredHeight() + mExpandedViewHeight - mScrolledParent.scrolledView.getMeasuredHeight());
for(int index = 0; index < mScrolledParent.childBetweenParentCount; index++) {
ViewGroup parent = (ViewGroup) getParent();
distance+=parent.getY();
}
return distance;
}
private void verticalAnimate(final int startHeight, final int endHeight ) {
int distance = getParentScrollDistance();
final View target = getChildAt(1);
mExpandAnimator = ValueAnimator.ofInt(startHeight,endHeight);
mExpandAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
target.getLayoutParams().height = (int) animation.getAnimatedValue();
target.requestLayout();
}
});
mExpandAnimator.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
if(endHeight-startHeight < 0) {
mExpandState = ExpandState.CLOSED;
if (mOnExpandListener != null) {
mOnExpandListener.onExpand(false);
}
} else {
mExpandState=ExpandState.EXPANDED;
if(mOnExpandListener != null) {
mOnExpandListener.onExpand(true);
}
}
}
});
mExpandState=mExpandState==ExpandState.EXPANDED?ExpandState.CLOSING :ExpandState.EXPANDING;
mExpandAnimator.setDuration(mSettings.expandDuration);
if(mExpandState == ExpandState.EXPANDING && mSettings.expandWithParentScroll && distance > 0) {
mParentAnimator = Utils.createParentAnimator(mScrolledParent.scrolledView, distance, mSettings.expandDuration);
mExpandScrollAnimatorSet = new AnimatorSet();
if(mSettings.expandScrollTogether) {
mExpandScrollAnimatorSet.playTogether(mExpandAnimator,mParentAnimator);
} else {
mExpandScrollAnimatorSet.playSequentially(mExpandAnimator,mParentAnimator);
}
mExpandScrollAnimatorSet.start();
} else {
mExpandAnimator.start();
}
}
public void setExpand(boolean expand) {
if (mExpandState == ExpandState.PRE_INIT) {return;}
getChildAt(1).getLayoutParams().height = expand ? mExpandedViewHeight : 0;
requestLayout();
mExpandState=expand?ExpandState.EXPANDED:ExpandState.CLOSED;
}
public boolean isExpanded() {
return mExpandState==ExpandState.EXPANDED;
}
public void toggle() {
if (isAllowedExpand){
if(mExpandState==ExpandState.EXPANDED) {
close();
}else if(mExpandState==ExpandState.CLOSED) {
expand();
}
}
}
public void expand() {
verticalAnimate(0,mExpandedViewHeight);
}
public void close() {
verticalAnimate(mExpandedViewHeight,0);
}
public interface OnExpandListener {
void onExpand(boolean expanded) ;
}
public void setOnExpandListener(OnExpandListener onExpandListener) {
this.mOnExpandListener = onExpandListener;
}
public void setExpandScrollTogether(boolean expandScrollTogether) {
this.mSettings.expandScrollTogether = expandScrollTogether;
}
public void setExpandWithParentScroll(boolean expandWithParentScroll) {
this.mSettings.expandWithParentScroll = expandWithParentScroll;
}
public void setExpandDuration(int expandDuration) {
this.mSettings.expandDuration = expandDuration;
}
#Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
Log.w("tag", "onDetachedFromWindow");
if(mExpandAnimator!=null&&mExpandAnimator.isRunning()) {
mExpandAnimator.cancel();
mExpandAnimator.removeAllUpdateListeners();
}
if(mParentAnimator!=null&&mParentAnimator.isRunning()) {
mParentAnimator.cancel();
mParentAnimator.removeAllUpdateListeners();
}
if(mExpandScrollAnimatorSet!=null) {
mExpandScrollAnimatorSet.cancel();
}
}
public void setAllowedExpand(boolean allowedExpand) {
isAllowedExpand = allowedExpand;
}
public void increaseDistance(int size){
if(mExpandState==ExpandState.EXPANDED) {
close();
}
mExpandedViewHeight = defaultHeight + size;
}
//func just for loggs
public void showParams(){
RelativeLayout relativeLayout = (RelativeLayout) getChildAt(1);
/*relativeLayout.requestLayout();
relativeLayout.invalidate();*/
RecyclerView recyclerView = (RecyclerView) relativeLayout.getChildAt(1);
Log.d("tag", "height - " + relativeLayout.getHeight());
Log.d("tag", "childs - " + relativeLayout.getChildCount());
Log.d("tag", "recycler height - " + recyclerView.getHeight());
recyclerView.requestLayout();
recyclerView.invalidateItemDecorations();
recyclerView.invalidate();
RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
layoutManager.getHeight();
Log.d("tag", " layoutManager.getHeight() - " + layoutManager.getHeight());
layoutManager.requestLayout();
layoutManager.generateDefaultLayoutParams();
layoutManager.onItemsChanged(recyclerView);
Log.d("tag", " layoutManager.getHeight()2- " + layoutManager.getHeight());
layoutManager.getChildCount();
recyclerView.getChildCount();
Log.d("tag", "manager childs - " + layoutManager.getChildCount());
Log.d("tag", "recycler childs - " + recyclerView.getChildCount());
}
}
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"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="#color/grey_light_color"
>
<com.example.develop.project.Utils.ExpandableView.ExpandableView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/test_custom_view"
app:expWithParentScroll="true"
android:layout_gravity="center"
android:background="#color/grey_color"
>
<android.support.v7.widget.CardView
android:id="#+id/start_card"
android:layout_width="match_parent"
android:layout_height="70dp"
android:background="#color/white_color"
android:layout_marginTop="5dp"
android:layout_marginStart="5dp"
android:layout_marginEnd="5dp"
>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/stage_tv4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#color/grey_deep_color"
android:text="Запуск"
android:layout_centerVertical="true"
android:layout_marginStart="15dp"
android:textSize="18sp"
/>
</RelativeLayout>
</android.support.v7.widget.CardView>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/start_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/start_accept"
android:textSize="18sp"
android:layout_marginStart="15dp"
android:layout_marginTop="15dp"
android:layout_marginBottom="15dp"
android:textColor="#color/grey_deep_color"
android:layout_marginEnd="15dp"
/>
<android.support.v7.widget.RecyclerView
android:id="#+id/my_test_tv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/start_tv"
android:layout_marginTop="10dp"
android:layout_marginStart="15dp"
android:layout_marginEnd="15dp"
>
</android.support.v7.widget.RecyclerView>
</RelativeLayout>
</com.example.develop.project.Utils.ExpandableView.ExpandableView>
<Button
android:id="#+id/add_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentStart="true"
android:text="Add elem"
android:layout_marginStart="15dp"
android:layout_marginBottom="15dp"
/>
<Button
android:id="#+id/check_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
android:text="Check params"
android:layout_marginBottom="15dp"
android:layout_marginEnd="15dp"
/>
</RelativeLayout>
Activity:
public class TestActivity extends MvpAppCompatActivity implements TestContract.View {
TestAdapter testAdapter;
#InjectPresenter
public TestPresenter presenter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test_layout);
init();
}
private void init() {
ExpandableView expandableView = findViewById(R.id.test_custom_view);
expandableView.setAllowedExpand(true);
Button add_btn = findViewById(R.id.add_btn);
Button check_btn = findViewById(R.id.check_btn);
add_btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
presenter.addElem();
}
});
check_btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
expandableView.showParams();
}
});
}
#Override
public void addElems(ArrayList<String> list) {
testAdapter.notifyDataSetChanged();
}
#Override
public void populateAdapter(ArrayList<String> list) {
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
RecyclerView recyclerView = findViewById(R.id.my_test_tv);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setNestedScrollingEnabled(false);
recyclerView.setHasFixedSize(false);
testAdapter = new TestAdapter(list);
recyclerView.setAdapter(testAdapter);
}
}
Adapter:
public class TestAdapter extends RecyclerView.Adapter<TestAdapter.TasksViewHolder> {
private List<String> list;
public TestAdapter(List<String> list) {
this.list = list;
}
#NonNull
#Override
public TestAdapter.TasksViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.test_item, parent, false);
TestAdapter.TasksViewHolder vh = new TestAdapter.TasksViewHolder(v);
return vh;
}
#Override
public void onBindViewHolder(#NonNull TestAdapter.TasksViewHolder holder, int position) {
String text = list.get(position);
holder.textView.setText(text);
}
public static class TasksViewHolder extends RecyclerView.ViewHolder {
private TextView textView;
public TasksViewHolder(View itemView) {
super(itemView);
textView = itemView.findViewById(R.id.my_test_tv);
}
}
#Override
public int getItemCount() {
return list.size();
}
}
The ExpandableView contains some suspicious code in its onMeasure method.
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
...
if(mIsInit) {
((MarginLayoutParams)getChildAt(0).getLayoutParams()).bottomMargin=0;
MarginLayoutParams marginLayoutParams = ((MarginLayoutParams)getChildAt(1).getLayoutParams());
marginLayoutParams.bottomMargin=0;
marginLayoutParams.topMargin=0;
marginLayoutParams.height = 0;
mExpandedViewHeight = getChildAt(1).getMeasuredHeight();
defaultHeight = mExpandedViewHeight;
mIsInit =false;
mExpandState = ExpandState.CLOSED;
View view = getChildAt(0);
if (view != null){
view.setOnClickListener(v -> toggle());
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
The mIsInit variable is set to true on creation and than to false when onMeasure is called for the first time. So the code in the condition runs only once.
But it stores value mExpandedViewHeight obtained as getChildAt(1).getMeasuredHeight() and that is current height of your relative layout, which contains (still empty) RecyclerView.
As far as I can see there's nothing in ExpadableView's code that would update this value, when you add an item to the Recylerview.
I am not sure, what would the correct/perfect implementation of the onMeasure method be (for your component). That would require some debugging and testing of the component, and perhaps some tweaks in other parts of the code.
If you wrote the component, you may want to invest more effort into debugging. If you didn't write the component, you should try to find other one, that is properly implemented. Custom components with custom measurements are an advanced topic.
If you really want to go with debugging and fixing your component, that first thing to do is to update the mExpandedViewHeight value on every measurement, but that might require updating other values that are derived from this value.
I want to enable flash on/off in my camera app, but it isn't working,
Here's the code:
FlashActivity.java
public class FlashActivity extends AppCompatActivity {
private CameraManager mCameraManager;
private String mCameraId;
private Button mTorchOnOffButton;
private Boolean isTorchOn;
private TextureView textureView;
SeekBar sb;
TextToSpeech t1;
private String cameraId;
private CameraDevice cameraDevice;
private CameraCaptureSession cameraCaptureSessions;
private CaptureRequest.Builder captureRequestBuilder;
private Size imageDimension;
Bitmap src;
private static final int REQUEST_CAMERA_PERMISSION = 200;
private Handler mBackgroundHandler;
private HandlerThread mBackgroundThread;
CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback()
{
#Override
public void onOpened(#NonNull CameraDevice camera) {
cameraDevice = camera;
createCameraPreview();
}
#Override
public void onDisconnected(#NonNull CameraDevice cameraDevice) {
cameraDevice.close();
}
#Override
public void onError(#NonNull CameraDevice cameraDevice, int i) {
cameraDevice.close();
cameraDevice=null;
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d("FlashActivity", "onCreate()");
setContentView(R.layout.activity_flash);
sb = (SeekBar) findViewById(R.id.seekBar2);
textureView = (TextureView) findViewById(R.id.textureView);
mTorchOnOffButton = (Button) findViewById(R.id.button_on_off);
isTorchOn = false;
textureView.setSurfaceTextureListener(textureListener);
t1 = new TextToSpeech(getApplicationContext(), new TextToSpeech.OnInitListener() {
#Override
public void onInit(int status) {
if (status != TextToSpeech.ERROR) {
t1.setLanguage(Locale.UK);
}
}
});
ToggleButton toggle = (ToggleButton) findViewById(R.id.toggleButton);
toggle.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
freeze();
String toSpeak = "Camera Freeze";
Toast.makeText(getApplicationContext(), toSpeak, Toast.LENGTH_SHORT).show();
t1.speak(toSpeak, TextToSpeech.QUEUE_FLUSH, null);
} else {
updatePreview();
String toSpeak = "Back to Live Camera";
Toast.makeText(getApplicationContext(), toSpeak, Toast.LENGTH_SHORT).show();
t1.speak(toSpeak, TextToSpeech.QUEUE_FLUSH, null);
}
}
});
Boolean isFlashAvailable = getApplicationContext().getPackageManager()
.hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH);
if (!isFlashAvailable) {
AlertDialog alert = new AlertDialog.Builder(FlashActivity.this)
.create();
alert.setTitle("Error !!");
alert.setMessage("Your device doesn't support flash light!");
alert.setButton(DialogInterface.BUTTON_POSITIVE, "OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// closing the application
finish();
System.exit(0);
}
});
alert.show();
return;
}
mCameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try {
mCameraId = mCameraManager.getCameraIdList()[0];
} catch (CameraAccessException e) {
e.printStackTrace();
}
mTorchOnOffButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
try {
if (isTorchOn) {
turnOffFlashLight();
isTorchOn = false;
} else {
turnOnFlashLight();
isTorchOn = true;
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
sb.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean b) {
float scale = ((progress / 10.0f) + 1);
textureView.setScaleX(scale);
textureView.setScaleY(scale);
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
}
public void turnOnFlashLight() {
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
mCameraManager.setTorchMode(mCameraId, true);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void turnOffFlashLight() {
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
mCameraManager.setTorchMode(mCameraId, false);
}
} catch (Exception e) {
e.printStackTrace();
}
}
ArrayList rev;
public void freeze() {
Thread td = new Thread(new Runnable() {
public void run() {
Bitmap bmp = textureView.getBitmap();
rev = new ArrayList<Bitmap>();
rev.add(bmp);
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(), "" + rev.size(), Toast.LENGTH_LONG).show();
try {
cameraCaptureSessions.stopRepeating();
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
});
}
});
td.start();
}
private void createCameraPreview() {
try {
SurfaceTexture texture = textureView.getSurfaceTexture();
assert texture != null;
texture.setDefaultBufferSize(imageDimension.getWidth(), imageDimension.getHeight());
Surface surface = new Surface(texture);
captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
captureRequestBuilder.addTarget(surface);
cameraDevice.createCaptureSession(Arrays.asList(surface), new CameraCaptureSession.StateCallback() {
#Override
public void onConfigured(#NonNull CameraCaptureSession cameraCaptureSession) {
if (cameraDevice == null)
return;
cameraCaptureSessions = cameraCaptureSession;
updatePreview();
}
#Override
public void onConfigureFailed(#NonNull CameraCaptureSession cameraCaptureSession) {
Toast.makeText(FlashActivity.this, "Changed", Toast.LENGTH_SHORT).show();
}
}, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private void updatePreview() {
if (cameraDevice == null)
Toast.makeText(this, "Error", Toast.LENGTH_SHORT).show();
captureRequestBuilder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO);
try {
cameraCaptureSessions.setRepeatingRequest(captureRequestBuilder.build(), null, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private void openCamera() {
CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try {
cameraId = manager.getCameraIdList()[0];
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
assert map != null;
imageDimension = map.getOutputSizes(SurfaceTexture.class)[0];
//Check realtime permission if run higher API 23
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{
Manifest.permission.CAMERA,
Manifest.permission.WRITE_EXTERNAL_STORAGE
}, REQUEST_CAMERA_PERMISSION);
return;
}
manager.openCamera(cameraId, stateCallback, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
TextureView.SurfaceTextureListener textureListener = new TextureView.SurfaceTextureListener() {
#Override
public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int i, int i1) {
openCamera();
}
#Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int i, int i1) {
}
#Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
return false;
}
#Override
public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
}
};
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
if(requestCode == REQUEST_CAMERA_PERMISSION)
{
if(grantResults[0] != PackageManager.PERMISSION_GRANTED)
{
Toast.makeText(this, "You can't use camera without permission", Toast.LENGTH_SHORT).show();
finish();
}
}
}
#Override
protected void onStop() {
super.onStop();
if(isTorchOn){
turnOffFlashLight();
}
}
#Override
protected void onPause() {
super.onPause();
if(isTorchOn){
turnOffFlashLight();
}
}
#Override
protected void onResume() {
super.onResume();
if(isTorchOn){
turnOnFlashLight();
}
}
}
Here's what I get at LOG
04-03 16:38:34.948 10905-10905/com.example.sumesh.myapplication W/System.err: android.hardware.camera2.CameraAccessException: The camera device is in use already
at android.hardware.camera2.utils.CameraBinderDecorator.throwOnError(CameraBinderDecorator.java:123)
at android.hardware.camera2.utils.CameraBinderDecorator$CameraBinderDecoratorListener.onAfterInvocation(CameraBinderDecorator.java:73)
at android.hardware.camera2.utils.Decorator.invoke(Decorator.java:81)
at java.lang.reflect.Proxy.invoke(Proxy.java:393)
at $Proxy0.setTorchMode(Unknown Source)
at android.hardware.camera2.CameraManager$CameraManagerGlobal.setTorchMode(CameraManager.java:884)
at android.hardware.camera2.CameraManager.setTorchMode(CameraManager.java:501)
at com.example.sumesh.myapplication.FlashActivity.turnOffFlashLight(FlashActivity.java:204)
at com.example.sumesh.myapplication.FlashActivity$5.onClick(FlashActivity.java:150)
at android.view.View.performClick(View.java:5215)
at android.view.View$PerformClick.run(View.java:21196)
}
I have used the linear layout instead of the relativeIlayout, but I
am unable to figure out what thing is exactly posing the error,
all the permissions are already defined in the android manifest,
any suggestions?
Try this , Full code for taking picture using camera2 API , Fragment_Camera4
/**
* A simple {#link Fragment} subclass.
*/
public class Fragment_Camera4 extends Fragment implements
AspectRatioFragment.Listener {
private View view;
private static final String TAG = "MainActivity";
private static final int REQUEST_CAMERA_PERMISSION = 1;
private static final String FRAGMENT_DIALOG = "dialog";
private static final int[] FLASH_OPTIONS = {
CameraView.FLASH_OFF,
CameraView.FLASH_ON,
};
private static final int[] FLASH_ICONS = {
R.drawable.ic_flash_off,
R.drawable.ic_flash_on,
};
private static final int[] FLASH_TITLES = {
R.string.flash_auto,
R.string.flash_off,
R.string.flash_on,
};
private int mCurrentFlash;
private CameraView mCameraView;
private Handler mBackgroundHandler;
private View.OnClickListener mOnClickListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.take_picture:
if (mCameraView != null) {
mCameraView.takePicture();
}
break;
case R.id.btn_switch_camera:
if (mCameraView != null) {
int facing = mCameraView.getFacing();
mCameraView.setFacing(facing == CameraView.FACING_FRONT ?
CameraView.FACING_BACK : CameraView.FACING_FRONT);
if (facing == CameraView.FACING_FRONT) {
btn_flash_onOff.setVisibility(View.VISIBLE);
} else {
btn_flash_onOff.setVisibility(View.GONE);
}
}
break;
case R.id.btn_flash_onOff:
if (mCameraView != null) {
mCurrentFlash = (mCurrentFlash + 1) % FLASH_OPTIONS.length;
btn_flash_onOff.setImageResource(FLASH_ICONS[mCurrentFlash]);
mCameraView.setFlash(FLASH_OPTIONS[mCurrentFlash]);
}
break;
}
}
};
ImageButton btn_flash_onOff;
public Fragment_Camera4() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
view = inflater.inflate(R.layout.fragment_fragment__camera4, container, false);
mCameraView = (CameraView) view.findViewById(R.id.camera);
if (mCameraView != null) {
mCameraView.addCallback(mCallback);
}
ImageButton fab = (ImageButton) view.findViewById(R.id.take_picture);
ImageButton btn_switch_camera = (ImageButton) view.findViewById(R.id.btn_switch_camera);
btn_flash_onOff = (ImageButton) view.findViewById(R.id.btn_flash_onOff);
if (fab != null) {
fab.setOnClickListener(mOnClickListener);
btn_switch_camera.setOnClickListener(mOnClickListener);
btn_flash_onOff.setOnClickListener(mOnClickListener);
}
return view;
}
#Override
public void onResume() {
super.onResume();
mCameraView.start();
}
#Override
public void onPause() {
mCameraView.stop();
super.onPause();
}
#Override
public void onDestroy() {
super.onDestroy();
if (mBackgroundHandler != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
mBackgroundHandler.getLooper().quitSafely();
} else {
mBackgroundHandler.getLooper().quit();
}
mBackgroundHandler = null;
}
}
#Override
public void onAspectRatioSelected(#NonNull AspectRatio ratio) {
if (mCameraView != null) {
Toast.makeText(getActivity(), ratio.toString(), Toast.LENGTH_SHORT).show();
mCameraView.setAspectRatio(ratio);
}
}
private Handler getBackgroundHandler() {
if (mBackgroundHandler == null) {
HandlerThread thread = new HandlerThread("background");
thread.start();
mBackgroundHandler = new Handler(thread.getLooper());
}
return mBackgroundHandler;
}
private CameraView.Callback mCallback
= new CameraView.Callback() {
#Override
public void onCameraOpened(CameraView cameraView) {
Log.d(TAG, "onCameraOpened");
}
#Override
public void onCameraClosed(CameraView cameraView) {
Log.d(TAG, "onCameraClosed");
}
#Override
public void onPictureTaken(CameraView cameraView, final byte[] data) {
Log.d(TAG, "onPictureTaken " + data.length);
Toast.makeText(cameraView.getContext(), R.string.picture_taken, Toast.LENGTH_SHORT)
.show();
getBackgroundHandler().post(new Runnable() {
#Override
public void run() {
String root = Environment.getExternalStorageDirectory().toString();
File myDir = new File(root + "/_saved_images");
myDir.mkdirs();
Random generator = new Random();
int n = 10000;
n = generator.nextInt(n);
String fname = "Image-" + n + ".jpg";
File file = new File(myDir, fname);
String final_path = myDir + "/" + fname;
OutputStream os = null;
try {
os = new FileOutputStream(file);
os.write(data);
os.close();
} catch (IOException e) {
Log.w(TAG, "Cannot write to " + file, e);
} finally {
if (os != null) {
try {
os.close();
} catch (IOException e) {
// Ignore
}
}
}
Bundle bundle = new Bundle();
bundle.putString("path", final_path);
bundle.putString("type", "picture");
Fragment_Post_Image_Detail post_image_detail = new Fragment_Post_Image_Detail();
post_image_detail.setArguments(bundle);
((BaseActivity) getActivity()).replaceFragmentWithBackstack(post_image_detail);
}
});
}
};
}
Then Cameraview class
import android.content.res.TypedArray;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.os.ParcelableCompat;
import android.support.v4.os.ParcelableCompatCreatorCallbacks;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.widget.FrameLayout;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Set;
public class CameraView extends FrameLayout {
/** The camera device faces the opposite direction as the device's screen. */
public static final int FACING_BACK = Constants.FACING_BACK;
/** The camera device faces the same direction as the device's screen. */
public static final int FACING_FRONT = Constants.FACING_FRONT;
/** Direction the camera faces relative to device screen. */
#IntDef({FACING_BACK, FACING_FRONT})
#Retention(RetentionPolicy.SOURCE)
public #interface Facing {
}
/** Flash will not be fired. */
public static final int FLASH_OFF = Constants.FLASH_OFF;
/** Flash will always be fired during snapshot. */
public static final int FLASH_ON = Constants.FLASH_ON;
/** Constant emission of light during preview, auto-focus and snapshot. */
public static final int FLASH_TORCH = Constants.FLASH_TORCH;
/** Flash will be fired automatically when required. */
public static final int FLASH_AUTO = Constants.FLASH_AUTO;
/** Flash will be fired in red-eye reduction mode. */
public static final int FLASH_RED_EYE = Constants.FLASH_RED_EYE;
/** The mode for for the camera device's flash control */
#IntDef({FLASH_OFF, FLASH_ON, FLASH_TORCH, FLASH_AUTO, FLASH_RED_EYE})
public #interface Flash {
}
CameraViewImpl mImpl;
private final CallbackBridge mCallbacks;
private boolean mAdjustViewBounds;
private final DisplayOrientationDetector mDisplayOrientationDetector;
public CameraView(Context context) {
this(context, null);
}
public CameraView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
#SuppressWarnings("WrongConstant")
public CameraView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
if (isInEditMode()){
mCallbacks = null;
mDisplayOrientationDetector = null;
return;
}
// Internal setup
final PreviewImpl preview = createPreviewImpl(context);
mCallbacks = new CallbackBridge();
if (Build.VERSION.SDK_INT < 21) {
mImpl = new Camera1(mCallbacks, preview);
} else if (Build.VERSION.SDK_INT < 23) {
mImpl = new Camera2(mCallbacks, preview, context);
} else {
mImpl = new Camera2Api23(mCallbacks, preview, context);
}
// Attributes
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CameraView, defStyleAttr,
R.style.Widget_CameraView);
mAdjustViewBounds = a.getBoolean(R.styleable.CameraView_android_adjustViewBounds, false);
setFacing(a.getInt(R.styleable.CameraView_facing, FACING_BACK));
String aspectRatio = a.getString(R.styleable.CameraView_aspectRatio);
if (aspectRatio != null) {
setAspectRatio(AspectRatio.parse(aspectRatio));
} else {
setAspectRatio(Constants.DEFAULT_ASPECT_RATIO);
}
setAutoFocus(a.getBoolean(R.styleable.CameraView_autoFocus, true));
setFlash(a.getInt(R.styleable.CameraView_flash, Constants.FLASH_AUTO));
a.recycle();
// Display orientation detector
mDisplayOrientationDetector = new DisplayOrientationDetector(context) {
#Override
public void onDisplayOrientationChanged(int displayOrientation) {
mImpl.setDisplayOrientation(displayOrientation);
}
};
}
#NonNull
private PreviewImpl createPreviewImpl(Context context) {
PreviewImpl preview;
if (Build.VERSION.SDK_INT < 14) {
preview = new SurfaceViewPreview(context, this);
} else {
preview = new TextureViewPreview(context, this);
}
return preview;
}
#Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (!isInEditMode()) {
mDisplayOrientationDetector.enable(ViewCompat.getDisplay(this));
}
}
#Override
protected void onDetachedFromWindow() {
if (!isInEditMode()) {
mDisplayOrientationDetector.disable();
}
super.onDetachedFromWindow();
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (isInEditMode()){
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
return;
}
// Handle android:adjustViewBounds
if (mAdjustViewBounds) {
if (!isCameraOpened()) {
mCallbacks.reserveRequestLayoutOnOpen();
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
return;
}
final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
if (widthMode == MeasureSpec.EXACTLY && heightMode != MeasureSpec.EXACTLY) {
final AspectRatio ratio = getAspectRatio();
assert ratio != null;
int height = (int) (MeasureSpec.getSize(widthMeasureSpec) * ratio.toFloat());
if (heightMode == MeasureSpec.AT_MOST) {
height = Math.min(height, MeasureSpec.getSize(heightMeasureSpec));
}
super.onMeasure(widthMeasureSpec,
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
} else if (widthMode != MeasureSpec.EXACTLY && heightMode == MeasureSpec.EXACTLY) {
final AspectRatio ratio = getAspectRatio();
assert ratio != null;
int width = (int) (MeasureSpec.getSize(heightMeasureSpec) * ratio.toFloat());
if (widthMode == MeasureSpec.AT_MOST) {
width = Math.min(width, MeasureSpec.getSize(widthMeasureSpec));
}
super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
heightMeasureSpec);
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
// Measure the TextureView
int width = getMeasuredWidth();
int height = getMeasuredHeight();
AspectRatio ratio = getAspectRatio();
if (mDisplayOrientationDetector.getLastKnownDisplayOrientation() % 180 == 0) {
ratio = ratio.inverse();
}
assert ratio != null;
if (height < width * ratio.getY() / ratio.getX()) {
mImpl.getView().measure(
MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(width * ratio.getY() / ratio.getX(),
MeasureSpec.EXACTLY));
} else {
mImpl.getView().measure(
MeasureSpec.makeMeasureSpec(height * ratio.getX() / ratio.getY(),
MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
}
}
#Override
protected Parcelable onSaveInstanceState() {
SavedState state = new SavedState(super.onSaveInstanceState());
state.facing = getFacing();
state.ratio = getAspectRatio();
state.autoFocus = getAutoFocus();
state.flash = getFlash();
return state;
}
#Override
protected void onRestoreInstanceState(Parcelable state) {
if (!(state instanceof SavedState)) {
super.onRestoreInstanceState(state);
return;
}
SavedState ss = (SavedState) state;
super.onRestoreInstanceState(ss.getSuperState());
setFacing(ss.facing);
setAspectRatio(ss.ratio);
setAutoFocus(ss.autoFocus);
setFlash(ss.flash);
}
/**
* Open a camera device and start showing camera preview. This is typically called from
* {#link Activity#onResume()}.
*/
public void start() {
if (!mImpl.start()) {
//store the state ,and restore this state after fall back o Camera1
Parcelable state=onSaveInstanceState();
// Camera2 uses legacy hardware layer; fall back to Camera1
mImpl = new Camera1(mCallbacks, createPreviewImpl(getContext()));
onRestoreInstanceState(state);
mImpl.start();
}
}
/**
* Stop camera preview and close the device. This is typically called from
* {#link Activity#onPause()}.
*/
public void stop() {
mImpl.stop();
}
/**
* #return {#code true} if the camera is opened.
*/
public boolean isCameraOpened() {
return mImpl.isCameraOpened();
}
/**
* Add a new callback.
*
* #param callback The {#link Callback} to add.
* #see #removeCallback(Callback)
*/
public void addCallback(#NonNull Callback callback) {
mCallbacks.add(callback);
}
/**
* Remove a callback.
*
* #param callback The {#link Callback} to remove.
* #see #addCallback(Callback)
*/
public void removeCallback(#NonNull Callback callback) {
mCallbacks.remove(callback);
}
/**
* #param adjustViewBounds {#code true} if you want the CameraView to adjust its bounds to
* preserve the aspect ratio of camera.
* #see #getAdjustViewBounds()
*/
public void setAdjustViewBounds(boolean adjustViewBounds) {
if (mAdjustViewBounds != adjustViewBounds) {
mAdjustViewBounds = adjustViewBounds;
requestLayout();
}
}
/**
* #return True when this CameraView is adjusting its bounds to preserve the aspect ratio of
* camera.
* #see #setAdjustViewBounds(boolean)
*/
public boolean getAdjustViewBounds() {
return mAdjustViewBounds;
}
/**
* Chooses camera by the direction it faces.
*
* #param facing The camera facing. Must be either {#link #FACING_BACK} or
* {#link #FACING_FRONT}.
*/
public void setFacing(#Facing int facing) {
mImpl.setFacing(facing);
}
/**
* Gets the direction that the current camera faces.
*
* #return The camera facing.
*/
#Facing
public int getFacing() {
//noinspection WrongConstant
return mImpl.getFacing();
}
/**
* Gets all the aspect ratios supported by the current camera.
*/
public Set<AspectRatio> getSupportedAspectRatios() {
return mImpl.getSupportedAspectRatios();
}
/**
* Sets the aspect ratio of camera.
*
* #param ratio The {#link AspectRatio} to be set.
*/
public void setAspectRatio(#NonNull AspectRatio ratio) {
if (mImpl.setAspectRatio(ratio)) {
requestLayout();
}
}
/**
* Gets the current aspect ratio of camera.
*
* #return The current {#link AspectRatio}. Can be {#code null} if no camera is opened yet.
*/
#Nullable
public AspectRatio getAspectRatio() {
return mImpl.getAspectRatio();
}
/**
* Enables or disables the continuous auto-focus mode. When the current camera doesn't support
* auto-focus, calling this method will be ignored.
*
* #param autoFocus {#code true} to enable continuous auto-focus mode. {#code false} to
* disable it.
*/
public void setAutoFocus(boolean autoFocus) {
mImpl.setAutoFocus(autoFocus);
}
/**
* Returns whether the continuous auto-focus mode is enabled.
*
* #return {#code true} if the continuous auto-focus mode is enabled. {#code false} if it is
* disabled, or if it is not supported by the current camera.
*/
public boolean getAutoFocus() {
return mImpl.getAutoFocus();
}
/**
* Sets the flash mode.
*
* #param flash The desired flash mode.
*/
public void setFlash(#Flash int flash) {
mImpl.setFlash(flash);
}
/**
* Gets the current flash mode.
*
* #return The current flash mode.
*/
#Flash
public int getFlash() {
//noinspection WrongConstant
return mImpl.getFlash();
}
/**
* Take a picture. The result will be returned to
* {#link Callback#onPictureTaken(CameraView, byte[])}.
*/
public void takePicture() {
mImpl.takePicture();
}
private class CallbackBridge implements CameraViewImpl.Callback {
private final ArrayList<Callback> mCallbacks = new ArrayList<>();
private boolean mRequestLayoutOnOpen;
CallbackBridge() {
}
public void add(Callback callback) {
mCallbacks.add(callback);
}
public void remove(Callback callback) {
mCallbacks.remove(callback);
}
#Override
public void onCameraOpened() {
if (mRequestLayoutOnOpen) {
mRequestLayoutOnOpen = false;
requestLayout();
}
for (Callback callback : mCallbacks) {
callback.onCameraOpened(CameraView.this);
}
}
#Override
public void onCameraClosed() {
for (Callback callback : mCallbacks) {
callback.onCameraClosed(CameraView.this);
}
}
#Override
public void onPictureTaken(byte[] data) {
for (Callback callback : mCallbacks) {
callback.onPictureTaken(CameraView.this, data);
}
}
public void reserveRequestLayoutOnOpen() {
mRequestLayoutOnOpen = true;
}
}
protected static class SavedState extends BaseSavedState {
#Facing
int facing;
AspectRatio ratio;
boolean autoFocus;
#Flash
int flash;
#SuppressWarnings("WrongConstant")
public SavedState(Parcel source, ClassLoader loader) {
super(source);
facing = source.readInt();
ratio = source.readParcelable(loader);
autoFocus = source.readByte() != 0;
flash = source.readInt();
}
public SavedState(Parcelable superState) {
super(superState);
}
#Override
public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags);
out.writeInt(facing);
out.writeParcelable(ratio, 0);
out.writeByte((byte) (autoFocus ? 1 : 0));
out.writeInt(flash);
}
public static final Parcelable.Creator<SavedState> CREATOR
= ParcelableCompat.newCreator(new ParcelableCompatCreatorCallbacks<SavedState>() {
#Override
public SavedState createFromParcel(Parcel in, ClassLoader loader) {
return new SavedState(in, loader);
}
#Override
public SavedState[] newArray(int size) {
return new SavedState[size];
}
});
}
/**
* Callback for monitoring events about {#link CameraView}.
*/
#SuppressWarnings("UnusedParameters")
public abstract static class Callback {
/**
* Called when camera is opened.
*
* #param cameraView The associated {#link CameraView}.
*/
public void onCameraOpened(CameraView cameraView) {
}
/**
* Called when camera is closed.
*
* #param cameraView The associated {#link CameraView}.
*/
public void onCameraClosed(CameraView cameraView) {
}
/**
* Called when a picture is taken.
*
* #param cameraView The associated {#link CameraView}.
* #param data JPEG data.
*/
public void onPictureTaken(CameraView cameraView, byte[] data) {
}
}
}
and xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:id="#+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/colorgrey">
<com.google.android.cameraview.CameraView
android:id="#+id/camera"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:adjustViewBounds="true"
android:background="#android:color/black" />
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true" />
<ImageButton
android:id="#+id/take_picture"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="20dp"
android:background="#0000"
app:srcCompat="#drawable/ic_take_pic" />
<ImageButton
android:id="#+id/btn_switch_camera"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_margin="20dp"
android:background="#0000"
app:srcCompat="#drawable/ic_reset_camera" />
<ImageButton
android:id="#+id/btn_flash_onOff"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_margin="20dp"
android:background="#0000"
app:srcCompat="#drawable/ic_flash_off" />
</RelativeLayout>
Also DONT FORGET TO ADD RUNTIME PERMISSIONS in OnCreate()
I have an activity which creates my custom SurfaceView for camera previewing in center of FrameLayout. In xml I have a FrameLayout with button and ImageView. When I click on button, I want ImageView shows over SurfaceView in center of FrameLayout. So when I run application I catch warning:
Skipped XX frames! The application may be doing too much work on its main thread
Here is my XML:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:orientation="vertical"
tools:context="com.rcd.perfecto.ui.CameraActivity">
<FrameLayout
android:id="#+id/fl_camera_preview"
android:layout_width="match_parent"
android:layout_height="match_parent">
<de.hdodenhof.circleimageview.CircleImageView
android:id="#+id/iv_avatar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
android:src="#drawable/ic_launcher"/>
<Button
android:id="#+id/btn_photo_capture"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/btn_photo_capture"
android:layout_gravity="center_horizontal|bottom"/>
</FrameLayout>
</LinearLayout>
Here is my custom SurfaceView
public class CameraView extends SurfaceView implements SurfaceHolder.Callback {
private Path mClipPath;
private Camera mCamera;
private WeakReference<FrameLayout> mFrameLayoutWeakReference;
private Context mContext;
private SurfaceHolder mHolder;
public CameraView(Context context) {
super(context);
init(context);
}
public CameraView(Context context, Camera camera, FrameLayout layout) {
super(context);
mCamera = camera;
mFrameLayoutWeakReference = new WeakReference<FrameLayout>(layout);
mHolder = getHolder();
mHolder.addCallback(this);
init(context);
}
public CameraView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public CameraView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public CameraView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context);
}
private void init(Context context) {
mContext = context;
WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = manager.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
float radius;
FrameLayout layout = mFrameLayoutWeakReference.get();
if (display.getRotation() == Surface.ROTATION_0 || display.getRotation() == Surface.ROTATION_180) {
radius = layout.getWidth() / 2;
} else {
radius = layout.getHeight() / 2;
}
mClipPath = new Path();
mClipPath.addCircle(layout.getWidth() / 2, layout.getHeight() / 2, radius, Path.Direction.CW);
}
#Override
protected void dispatchDraw(Canvas canvas) {
canvas.clipPath(mClipPath);
super.dispatchDraw(canvas);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
try {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if (mHolder.getSurface() == null) {
return;
}
try {
mCamera.stopPreview();
} catch (Exception e) {
e.printStackTrace();
}
Camera.Parameters parameters = mCamera.getParameters();
Display display = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
if (display.getRotation() == Surface.ROTATION_0) {
parameters.setPreviewSize(height, width);
mCamera.setDisplayOrientation(90);
}
if (display.getRotation() == Surface.ROTATION_90) {
parameters.setPreviewSize(width, height);
}
if (display.getRotation() == Surface.ROTATION_180) {
parameters.setPreviewSize(height, width);
}
if (display.getRotation() == Surface.ROTATION_270) {
parameters.setPreviewSize(width, height);
mCamera.setDisplayOrientation(180);
}
try {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
}
And my activity:
public class CameraActivity extends AppCompatActivity {
#Bind(R.id.btn_photo_capture) Button mPhotoCaptureButton;
#Bind(R.id.fl_camera_preview) FrameLayout mCameraPreviewFrameLayout;
#Bind(R.id.iv_avatar) CircleImageView mAvatarImageView;
private Camera mCamera;
private CameraView mCameraView;
public CameraActivity() {
}
#OnClick(R.id.btn_photo_capture)
void takePicture() {
if (mAvatarImageView.getVisibility() == View.VISIBLE) {
mAvatarImageView.setVisibility(View.GONE);
} else {
mAvatarImageView.setVisibility(View.VISIBLE);
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera);
ButterKnife.bind(this);
if (checkCameraHardware()) {
if (Camera.getNumberOfCameras() > 1) {
mCamera = getCameraInstance(Camera.CameraInfo.CAMERA_FACING_FRONT);
} else mCamera = getCameraInstance();
}
ViewTreeObserver observer = mCameraPreviewFrameLayout.getViewTreeObserver();
observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
mCameraView = new CameraView(CameraActivity.this, mCamera, mCameraPreviewFrameLayout);
mCameraPreviewFrameLayout.addView(mCameraView, 0);
}
});
}
private static Camera getCameraInstance() {
Camera c = null;
try {
c = Camera.open();
} catch (Exception e) {
e.printStackTrace();
}
return c;
}
private static Camera getCameraInstance(int id) {
Camera c = null;
try {
c = Camera.open(id);
} catch (Exception e) {
e.printStackTrace();
}
return c;
}
private boolean checkCameraHardware() {
return getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA);
}
}
So my question is how can I avoid warning above or is there another way to set surfaceview in center of FrameLayout programmatically?
I'm trying to upload an Image from my API to show it as profile picture, the problem is from the first time that the user opens the navdrawer the image doesn't load and it makes the entire layout disappear, but from the second time it all works, and I notice that it happens when the width of the image is less than the height. This is the class that I'm using:
public class CircledNetworkImageView extends ImageView {
public boolean mCircled;
/**
* The URL of the network image to load
*/
private String mUrl;
/**
* Resource ID of the image to be used as a placeholder until the network image is loaded.
*/
private int mDefaultImageId;
/**
* Resource ID of the image to be used if the network response fails.
*/
private int mErrorImageId;
/**
* Local copy of the ImageLoader.
*/
private ImageLoader mImageLoader;
/**
* Current ImageContainer. (either in-flight or finished)
*/
private ImageLoader.ImageContainer mImageContainer;
public CircledNetworkImageView(Context context) {
this(context, null);
}
public CircledNetworkImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CircledNetworkImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
/**
* Sets URL of the image that should be loaded into this view. Note that calling this will
* immediately either set the cached image (if available) or the default image specified by
* {#link CircledNetworkImageView#setDefaultImageResId(int)} on the view.
* <p/>
* NOTE: If applicable, {#link CircledNetworkImageView#setDefaultImageResId(int)} and
* {#link CircledNetworkImageView#setErrorImageResId(int)} should be called prior to calling
* this function.
*
* #param url The URL that should be loaded into this ImageView.
* #param imageLoader ImageLoader that will be used to make the request.
*/
public void setImageUrl(String url, ImageLoader imageLoader) {
mUrl = url;
mImageLoader = imageLoader;
// The URL has potentially changed. See if we need to load it.
loadImageIfNecessary(false);
}
/**
* Sets the default image resource ID to be used for this view until the attempt to load it
* completes.
*/
public void setDefaultImageResId(int defaultImage) {
mDefaultImageId = defaultImage;
}
/**
* Sets the error image resource ID to be used for this view in the event that the image
* requested fails to load.
*/
public void setErrorImageResId(int errorImage) {
mErrorImageId = errorImage;
}
/**
* Loads the image for the view if it isn't already loaded.
*
* #param isInLayoutPass True if this was invoked from a layout pass, false otherwise.
*/
void loadImageIfNecessary(final boolean isInLayoutPass) {
int width = getWidth();
int height = getHeight();
ScaleType scaleType = getScaleType();
boolean wrapWidth = false, wrapHeight = false;
if (getLayoutParams() != null) {
wrapWidth = getLayoutParams().width == ViewGroup.LayoutParams.WRAP_CONTENT;
wrapHeight = getLayoutParams().height == ViewGroup.LayoutParams.WRAP_CONTENT;
}
// if the view's bounds aren't known yet, and this is not a wrap-content/wrap-content
// view, hold off on loading the image.
boolean isFullyWrapContent = wrapWidth && wrapHeight;
if (width == 0 && height == 0 && !isFullyWrapContent) {
return;
}
// if the URL to be loaded in this view is empty, cancel any old requests and clear the
// currently loaded image.
if (TextUtils.isEmpty(mUrl)) {
if (mImageContainer != null) {
mImageContainer.cancelRequest();
mImageContainer = null;
}
setDefaultImageOrNull();
return;
}
// if there was an old request in this view, check if it needs to be canceled.
if (mImageContainer != null && mImageContainer.getRequestUrl() != null) {
if (mImageContainer.getRequestUrl().equals(mUrl)) {
// if the request is from the same URL, return.
return;
} else {
// if there is a pre-existing request, cancel it if it's fetching a different URL.
mImageContainer.cancelRequest();
setDefaultImageOrNull();
}
}
// Calculate the max image width / height to use while ignoring WRAP_CONTENT dimens.
int maxWidth = wrapWidth ? 0 : width;
int maxHeight = wrapHeight ? 0 : height;
// The pre-existing content of this view didn't match the current URL. Load the new image
// from the network.
ImageLoader.ImageContainer newContainer = mImageLoader.get(mUrl,
new ImageLoader.ImageListener() {
#Override
public void onErrorResponse(VolleyError error) {
if (mErrorImageId != 0) {
setImageResource(mErrorImageId);
}
}
#Override
public void onResponse(final ImageLoader.ImageContainer response, boolean isImmediate) {
// If this was an immediate response that was delivered inside of a layout
// pass do not set the image immediately as it will trigger a requestLayout
// inside of a layout. Instead, defer setting the image by posting back to
// the main thread.
if (isImmediate && isInLayoutPass) {
post(new Runnable() {
#Override
public void run() {
onResponse(response, false);
}
});
return;
}
if (response.getBitmap() != null) {
setImageBitmap(response.getBitmap());
} else if (mDefaultImageId != 0) {
setImageResource(mDefaultImageId);
}
}
}, maxWidth, maxHeight, scaleType);
// update the ImageContainer to be the new bitmap container.
mImageContainer = newContainer;
}
private void setDefaultImageOrNull() {
if (mDefaultImageId != 0) {
setImageResource(mDefaultImageId);
} else {
setImageBitmap(null);
}
}
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
loadImageIfNecessary(true);
}
#Override
protected void onDetachedFromWindow() {
if (mImageContainer != null) {
// If the view was bound to an image request, cancel it and clear
// out the image from the view.
mImageContainer.cancelRequest();
setImageBitmap(null);
// also clear out the container so we can reload the image if necessary.
mImageContainer = null;
}
super.onDetachedFromWindow();
}
#Override
protected void drawableStateChanged() {
super.drawableStateChanged();
invalidate();
}
/**
* In case the bitmap is manually changed, we make sure to
* circle it on the next onDraw
*/
#Override
public void setImageBitmap(Bitmap bm) {
mCircled = false;
super.setImageBitmap(bm);
}
/**
* In case the bitmap is manually changed, we make sure to
* circle it on the next onDraw
*/
#Override
public void setImageResource(int resId) {
mCircled = false;
super.setImageResource(resId);
}
/**
* In case the bitmap is manually changed, we make sure to
* circle it on the next onDraw
*/
#Override
public void setImageDrawable(Drawable drawable) {
mCircled = false;
super.setImageDrawable(drawable);
}
/**
* We want to make sure that the ImageView has the same height and width
*/
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Drawable drawable = getDrawable();
if (drawable != null) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int diw = drawable.getIntrinsicWidth();
if (diw > 0) {
int height = width * drawable.getIntrinsicHeight() / diw;
setMeasuredDimension(width, height);
} else
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
} else
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
#Override
protected void onDraw(Canvas canvas) {
//Let's circle the image
if (!mCircled && getDrawable() != null) {
Drawable d = getDrawable();
try {
//We use reflection here in case that the drawable isn't a
//BitmapDrawable but it contains a public getBitmap method.
Bitmap bitmap = (Bitmap) d.getClass().getMethod("getBitmap").invoke(d);
if (bitmap != null) {
Bitmap circleBitmap = getCircleBitmap(bitmap);
setImageBitmap(circleBitmap);
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
//Seems like the current drawable is not a BitmapDrawable or
//that is doesn't have a public getBitmap() method.
}
//Mark as circled even if it failed, because if it fails once,
//It will fail again.
mCircled = true;
}
super.onDraw(canvas);
}
/**
* Method used to circle a bitmap.
*
* #param bitmap The bitmap to circle
* #return The circled bitmap
*/
public static Bitmap getCircleBitmap(Bitmap bitmap) {
int size = Math.min(bitmap.getWidth(), bitmap.getHeight());
Bitmap output = Bitmap.createBitmap(size,
size, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(output);
BitmapShader shader;
shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP,
Shader.TileMode.CLAMP);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setShader(shader);
paint.setAlpha(254);
RectF rect = new RectF(0, 0, size, size);
int radius = size / 2;
canvas.drawRoundRect(rect, radius, radius, paint);
return output;
}
}
I came up with that solution, but I didn't like it, because the image loses its quality:
public class UserActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.profile_main);
toolbar = (Toolbar) findViewById(R.id.toolbar_user);
camera = (ImageView) findViewById(R.id.camera);
fechar = (TextView) findViewById(R.id.fechar);
editar = (TextView) findViewById(R.id.editar);
membro = (TextView) findViewById(R.id.membro);
nome = (TextView) findViewById(R.id.nome_usuario);
email = (TextView) findViewById(R.id.email_usuario);
email = (TextView) findViewById(R.id.email_usuario);
profilePic = (NetworkImageView) findViewById(R.id.foto);
mImageView = (ImageView) findViewById(R.id.cropped);
progress_wheel = (ProgressWheel) findViewById(R.id.progress_wheel);
camera.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
AlertDialog.Builder getImageFrom = new AlertDialog.Builder(UserActivity.this);
getImageFrom.setTitle("Abrir com:");
final CharSequence[] opsChars = {getResources().getString(R.string.takepic), getResources().getString(R.string.opengallery)};
getImageFrom.setItems(opsChars, new android.content.DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
if (which == 0) {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
mImageCaptureUri = Uri.fromFile(new File(Environment.getExternalStorageDirectory(),
"tmp_avatar_" + String.valueOf(System.currentTimeMillis()) + ".jpg"));
intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, mImageCaptureUri);
try {
intent.putExtra("return-data", true);
startActivityForResult(intent, PICK_FROM_CAMERA);
} catch (ActivityNotFoundException e) {
e.printStackTrace();
}
} else if (which == 1) {
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent, "Complete action using"), PICK_FROM_FILE);
}
dialog.dismiss();
}
});
getImageFrom.show();
}
});
profilePic.setImageUrl(GlobalModel.getPerfil().getIdDaImagem(), imageLoader);
profilePic.setDefaultImageResId(R.drawable.avatar_);
}
#Override
public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
super.onActivityResult(requestCode, resultCode, data);
try {
if (resultCode != RESULT_OK) return;
switch (requestCode) {
case PICK_FROM_CAMERA:
profilePic.setVisibility(View.GONE);
progress_wheel.setVisibility(View.VISIBLE);
selectedImagePath = ImageFilePath.getPath(getApplicationContext(), mImageCaptureUri);
Log.i("Image File Path", "" + selectedImagePath);
mImageCaptureUri = Uri.parse(selectedImagePath);
final BitmapFactory.Options option = new BitmapFactory.Options();
option.inSampleSize = 8;
Bitmap photo = BitmapFactory.decodeFile(mImageCaptureUri.getPath(), option);
photo = Bitmap.createScaledBitmap(photo, 200, 200, false);
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
photo.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
File f = new File(Environment.getExternalStorageDirectory()
+ File.separator + "Imagename.jpg");
f.createNewFile();
FileOutputStream fo = new FileOutputStream(f);
fo.write(bytes.toByteArray());
fo.close();
previewCapturedImage(f.getAbsolutePath());
profilePic.setVisibility(View.VISIBLE);
progress_wheel.setVisibility(View.GONE);
profilePic.setImageBitmap(BitmapFactory.decodeFile(mImageCaptureUri.getPath()));
break;
case PICK_FROM_FILE:
profilePic.setVisibility(View.GONE);
progress_wheel.setVisibility(View.VISIBLE);
mImageCaptureUri = data.getData();
selectedImagePath = ImageFilePath.getPath(getApplicationContext(), mImageCaptureUri);
Log.i("Image File Path", "" + selectedImagePath);
mImageCaptureUri = Uri.parse(selectedImagePath);
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 8;
Bitmap photoGaleria = BitmapFactory.decodeFile(mImageCaptureUri.getPath(), options);
photoGaleria = Bitmap.createScaledBitmap(photoGaleria, 200, 200, false);
ByteArrayOutputStream bytesG = new ByteArrayOutputStream();
photoGaleria.compress(Bitmap.CompressFormat.JPEG, 100, bytesG);
File fG = new File(Environment.getExternalStorageDirectory()
+ File.separator + "Imagename.jpg");
fG.createNewFile();
FileOutputStream foG = new FileOutputStream(fG);
foG.write(bytesG.toByteArray());
foG.close();
previewCapturedImage(fG.getAbsolutePath());
profilePic.setVisibility(View.VISIBLE);
progress_wheel.setVisibility(View.GONE);
profilePic.setImageBitmap(BitmapFactory.decodeFile(mImageCaptureUri.getPath()));
break;
}
} catch (Exception e)
{
e.printStackTrace();
}
}
private void previewCapturedImage(String path) {
try {
UploadFoto mUpload = new UploadFoto(path);
mUpload.setEventoListener(new IExecutarTarefa<UploadFoto>() {
#Override
public void AntesDeExecutar(UploadFoto tarefa) {
}
#Override
public void DepoisDeExecutar(UploadFoto tarefa) {
if (tarefa.getResposta()[0].equals("200")) {
GlobalModel.getPerfil().setIdDaImagem(WebService.imgURL + tarefa.getResposta()[1].replace("\"", ""));
profilePic.setImageUrl(GlobalModel.getPerfil().getIdDaImagem(), imageLoader);
}
}
});
mUpload.execute();
} catch (NullPointerException e) {
e.printStackTrace();
}
}
#Override
public void onBackPressed() {
super.onBackPressed();
finish();
overridePendingTransition(R.anim.animation_back, R.anim.animation_back_leave);
}
#Override
protected void onResume() {
super.onResume();
CarregarPerfil mCarrega = new CarregarPerfil();
mCarrega.execute();
}
}
XML:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res-auto"
xmlns:wheel="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:orientation="vertical">
<include
android:id="#+id/toolbar_user"
layout="#layout/toolbaruser" />
<RelativeLayout
android:id="#+id/campoImagem"
android:layout_width="fill_parent"
android:layout_height="200dp"
android:layout_below="#+id/toolbar_user"
android:background="#color/armadillo">
<com.android.volley.toolbox.NetworkImageView
android:id="#+id/foto"
android:layout_width="200dp"
android:layout_height="fill_parent"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:adjustViewBounds="true"
android:scaleType="centerCrop"
android:src="#drawable/user"
android:visibility="visible" />
<com.pnikosis.materialishprogress.ProgressWheel
android:id="#+id/progress_wheel"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_gravity="center"
android:visibility="gone"
wheel:matProg_barColor="#color/white"
wheel:matProg_progressIndeterminate="true"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true" />
<ImageView
android:id="#+id/cropped"
android:layout_width="200dp"
android:layout_height="fill_parent"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:layout_gravity="center"
android:visibility="visible"/>
<ImageView
android:id="#+id/camera"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:padding="15dp"
android:src="#drawable/ic_camera" />
<TextView
android:id="#+id/Button_crop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:gravity="center"
android:padding="15dp"
android:text="Salvar"
android:textColor="#color/white"
android:visibility="gone" />
</RelativeLayout>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true">
<TextView
android:id="#+id/membro"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:gravity="center"
android:paddingBottom="10dp"
android:paddingLeft="10dp"
android:paddingTop="5dp"
android:text="Membro Retornar desde Julho de 2015"
android:textColor="#color/star_dust" />
</RelativeLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/campoImagem"
android:layout_marginBottom="30dp"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:layout_marginTop="15dp"
android:gravity="center"
android:orientation="vertical">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="left"
android:paddingBottom="0dp"
android:paddingLeft="10dp"
android:paddingRight="0dp"
android:paddingTop="10dp"
android:text="Nome"
android:textColor="#color/star_dust"
android:textSize="#dimen/text1" />
<TextView
android:id="#+id/nome_usuario"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="left"
android:paddingBottom="0dp"
android:paddingLeft="10dp"
android:paddingTop="5dp"
android:textColor="#color/armadillo"
android:textSize="#dimen/text1" />
<TextView
android:id="#+id/entrar"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="left"
android:paddingLeft="10dp"
android:paddingTop="10dp"
android:text="E-mail"
android:textColor="#color/star_dust"
android:textSize="#dimen/text1" />
<TextView
android:id="#+id/email_usuario"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="left"
android:paddingBottom="0dp"
android:paddingLeft="10dp"
android:paddingTop="5dp"
android:text="jgvidotto#gmail.com"
android:textColor="#color/armadillo"
android:textSize="#dimen/text1" />
</LinearLayout>
</RelativeLayout>
Because you have not posted your Activity calling the Navigation Drawer, so I have used both your CircledNetworkImageView class and built-in NetworkImageView in my project. It works well. Please refer to the following:
CustomNavigationDrawer.java:
public class CustomNavigationDrawer {
private static ActionBarDrawerToggle sDrawerToggle;
public static DrawerLayout setUpDrawer(final Context context) {
final Activity activity = ((Activity) context);
DrawerLayout sDrawerLayout = (DrawerLayout) activity.findViewById(R.id.drawer_layout);
if (activity.getActionBar() != null) {
activity.getActionBar().setDisplayHomeAsUpEnabled(true);
activity.getActionBar().setHomeButtonEnabled(true);
}
sDrawerToggle = new ActionBarDrawerToggle(
activity,
sDrawerLayout,
R.drawable.ic_drawer,
R.string.drawer_open,
R.string.drawer_close
) {
public void onDrawerClosed(View view) {
activity.invalidateOptionsMenu();
syncState();
}
public void onDrawerOpened(View drawerView) {
activity.invalidateOptionsMenu();
syncState();
}
};
sDrawerLayout.setDrawerListener(sDrawerToggle);
return sDrawerLayout;
}
public static void syncState() {
sDrawerToggle.syncState();
}
public static void onConfigurationChanged(Configuration newConfig) {
sDrawerToggle.onConfigurationChanged(newConfig);
}
}
MainActivity.java:
public class MainActivity extends Activity {
final Context mContext = this;
final String mUrl = "http://.../getimage";
NetworkImageView mNetworkImageView;
CircledNetworkImageView mCircledNetworkImageView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
CustomNavigationDrawer.setUpDrawer(this);
mNetworkImageView = (NetworkImageView) findViewById(R.id.networkImageView);
mNetworkImageView.setImageUrl(mUrl, VolleySingleton.getInstance(mContext).getImageLoader());
mCircledNetworkImageView = (CircledNetworkImageView) findViewById(R.id.circleImageView);
mCircledNetworkImageView.setImageUrl(mUrl, VolleySingleton.getInstance(mContext).getImageLoader());
}
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
CustomNavigationDrawer.syncState();
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
CustomNavigationDrawer.onConfigurationChanged(newConfig);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
}
activity_main.xml:
<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:context=".MainActivity">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="start"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin">
<com.android.volley.toolbox.NetworkImageView
android:id="#+id/networkImageView"
android:layout_width="300dp"
android:layout_height="wrap_content" />
<com.example.networkimageview.CircledNetworkImageView
android:id="#+id/circleImageView"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_below="#+id/networkImageView" />
</RelativeLayout>
</android.support.v4.widget.DrawerLayout>
You can create a new sample project and use my sample code. Hope this helps!
if (width == 0 && height == 0 && !isFullyWrapContent) {
I guess the first you loadImage code will return because of this condition. The width and height is equal to 0 before the whole UI load success. log before this condition return. Hope this can help you.
I have not found any way to crop camera ppreview and then display it on the SurfaceView.
Android - Is it possible to crop camera preview?
You can do this without overlay views (which won't work in all situations).
Subclass ViewGroup, add the SurfaceView as the only child, then:
in onMeasure supply the cropped dimensions you want.
in onLayout, layout the SurfaceView with the un-cropped dimensions.
basically,
public class CroppedCameraPreview extends ViewGroup {
private SurfaceView cameraPreview;
public CroppedCameraPreview( Context context ) {
super( context );
// i'd probably create and add the SurfaceView here, but it doesn't matter
}
#Override
protected void onMeasure( int widthMeasureSpec, int heightMeasureSpec ) {
setMeasuredDimension( croppedWidth, croppedHeight );
}
#Override
protected void onLayout( boolean changed, int l, int t, int r, int b ) {
if ( cameraPreview != null ) {
cameraPreview.layout( 0, 0, actualPreviewWidth, actualPreviewHeight );
}
}
}
You could put the camera preview (SurfaceView) inside a LinearLayout that is inside a ScrollView. When the camera output is bigger than the LinearLayout you set you can programmatically scroll it and disable user scroll. This way you can emulate camera cropping in an easy way:
<ScrollView
android:id="#+id/scrollView"
android:layout_width="640dip"
android:layout_height="282dip"
android:scrollbars="none"
android:fillViewport="true">
<LinearLayout
android:id="#+id/linearLayoutBeautyContent"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<SurfaceView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/surfaceViewBeautyCamera"/>
</LinearLayout>
</ScrollView>
Not directly. Camera API does now allow for offsets, and will squeeze image into surface
holder. But you can work around by placing overlays (other views) over it.
The code to programmatically scroll the image would be something like this:
public void setCameraOrientationOnOpen()
{
mCamera.stopPreview();
int rotation = getRotation();
Camera.Parameters currentCameraParameters = mCamera.getParameters();
List<Camera.Size> previewSizes = currentCameraParameters.getSupportedPreviewSizes();
mOptimalCameraSize = getOptimaPreviewCameraSize(previewSizes, (double)9/16);
currentCameraParameters.setPreviewSize(mOptimalCameraSize.width, mOptimalCameraSize.height);
mCamera.setParameters(currentCameraParameters);
float ratio = 100;
int ratio1 = (mSurfaceView.getLayoutParams().height * 100) / mOptimalCameraSize.width; //height
int ratio2 = (mSurfaceView.getLayoutParams().width * 100) / mOptimalCameraSize.height; //width
ratio = Math.max(ratio1, ratio2);
mSurfaceView.getLayoutParams().height = (int) ((mOptimalCameraSize.width * ratio) / 100);
mSurfaceView.getLayoutParams().width = (int) ((mOptimalCameraSize.height * ratio) / 100);
if(ratio > 100)
{
int offset = (mSurfaceView.getLayoutParams().height - mBoxHeight)/2;
mScrollView.scrollTo(0, offset); //center the image
}
mCamera.setDisplayOrientation(rotation);
mOptimalCameraSize = mCamera.getParameters().getPreviewSize();
}
I calculate the best preview size from the camera for my camera content box (ratio 16:9), then apply the calculated ratio to the image in order to keep the same ratio and finally calculate the needed scroll (the image would be on the middle)
Create a centered Frame Layout that will store the Camera Preview and overlay it with Views to "crop" it. When you create your view, dynamically stretch a transparent view that is centered as well.
XML:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000" >
<FrameLayout
android:id="#+id/camera_preview_frame"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_centerVertical="true" />
<View
android:id="#+id/transparent_window"
android:layout_width="fill_parent"
android:layout_height="50dip"
android:layout_centerVertical="true"
android:background="#android:color/transparent" />
<View
android:id="#+id/black_top_box"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_above="#id/transparent_window"
android:background="#000"/>
<View
android:id="#+id/black_bottom_box"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_below="#id/transparent_window"
android:background="#000"/>
</RelativeLayout>
Then in the OnCreate() method of your activity class you can stretch the transparent view like this.
CameraActivity.java
final View transView = findViewById(R.id.transparent_window);
transView.post(new Runnable() {
#Override
public void run() {
RelativeLayout.LayoutParams params;
params = (RelativeLayout.LayoutParams) transView.getLayoutParams();
params.height = transView.getWidth();
transView.setLayoutParams(params);
transView.postInvalidate();
}
});
This is a screenshot from my phone of this. The gray blob in the middle is the camera's view of the floor through the transparent View
Here is a solution for orientation = landscape to complete #drees' excellent answer.
Just add layout-land folder in res folder, duplicate your entire layout xml and change the layout part of #drees' code to be like this:
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/background_dark" >
<FrameLayout
android:id="#+id/frameSurface"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:background="#android:color/background_light"/>
<View
android:id="#+id/transparent_window"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_centerInParent="true"
android:background="#android:color/transparent" />
<View
android:id="#+id/black_top_box"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_toLeftOf="#id/transparent_window"
android:background="#android:color/background_dark"/>
<View
android:id="#+id/black_bottom_box"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_toRightOf="#id/transparent_window"
android:background="#android:color/background_dark"/>
</RelativeLayout>
This solution is one of more of work arounds for your situation. Some code is deprecated and not recommended to use in enterprise projects, but if you need just show a camera preview without squeeze it's enough.
If you need handle image before preview then you should look SurfaceTexture
public class CameraPreview
extends SurfaceView
implements SurfaceHolder.Callback, Camera.PreviewCallback {
public static final String TAG = CameraPreview.class.getSimpleName();
private static final int PICTURE_SIZE_MAX_WIDTH = 1280;
private static final int PREVIEW_SIZE_MAX_WIDTH = 640;
private static final double ASPECT_RATIO = 3.0 / 4.0;
private Camera mCamera;
private SurfaceHolder mHolder;
private boolean mIsLive;
private boolean mIsPreviewing;
public CameraPreview(Context context) {
super(context);
init(context);
}
public CameraPreview(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public CameraPreview(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = (int) (width / ASPECT_RATIO + 0.5);
setMeasuredDimension(width, height);
}
#Override
protected void onVisibilityChanged(#NonNull View changedView, int visibility) {
super.onVisibilityChanged(changedView, visibility);
//L.g().d(TAG, "onVisibilityChanged: visibility=" + visibility);
if (mIsLive) {
if (visibility == VISIBLE && !mIsPreviewing) {
startCameraPreview();
} else {
stopCameraPreview();
}
}
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
startCamera();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
stopCamera();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
//L.g().d(TAG, "surfaceChanged: format=" + format + ", width=" + w + ", height=" + h);
if (mHolder.getSurface() == null || mCamera == null) return;
mHolder = holder;
try {
mCamera.stopPreview();
} catch (Exception ignored) {}
try {
mCamera.setPreviewDisplay(mHolder);
if (mIsLive && mIsPreviewing) mCamera.startPreview();
} catch (Exception ignored) {}
}
#Override
public void onPreviewFrame(byte[] data, Camera camera) {
//work with camera preview
if (mIsPreviewing) camera.setOneShotPreviewCallback(this);
}
private Camera.Size determineBestPreviewSize(Camera.Parameters parameters) {
return determineBestSize(parameters.getSupportedPreviewSizes(), PREVIEW_SIZE_MAX_WIDTH);
}
private Camera.Size determineBestPictureSize(Camera.Parameters parameters) {
return determineBestSize(parameters.getSupportedPictureSizes(), PICTURE_SIZE_MAX_WIDTH);
}
/**
* This code I found in this repository
* https://github.com/boxme/SquareCamera/blob/master/squarecamera/src/main/java/com/desmond/squarecamera/CameraFragment.java#L368
*/
private Camera.Size determineBestSize(List<Camera.Size> sizes, int widthThreshold) {
Camera.Size bestSize = null;
Camera.Size size;
int numOfSizes = sizes.size();
for (int i = 0; i < numOfSizes; i++) {
size = sizes.get(i);
boolean isDesireRatio = (size.width / 4) == (size.height / 3);
boolean isBetterSize = (bestSize == null) || size.width > bestSize.width;
if (isDesireRatio && isBetterSize) {
bestSize = size;
}
}
if (bestSize == null) {
return sizes.get(sizes.size() - 1);
}
return bestSize;
}
private void init(Context context) {
mHolder = getHolder();
mHolder.addCallback(this);
}
public void startCamera() {
if (!mIsLive) {
//L.g().d(TAG, "startCamera");
mIsPreviewing = false;
mCamera = Camera.open();
if (mCamera != null) {
try {
Camera.Parameters param = mCamera.getParameters();
Camera.Size bestPreviewSize = determineBestPreviewSize(param);
Camera.Size bestPictureSize = determineBestPictureSize(param);
param.setPreviewSize(bestPreviewSize.width, bestPreviewSize.height);
param.setPictureSize(bestPictureSize.width, bestPictureSize.height);
mCamera.setParameters(param);
} catch (RuntimeException ignored) {}
try {
mCamera.setDisplayOrientation(90);
mCamera.setPreviewCallback(this);
mCamera.setPreviewDisplay(mHolder);
mIsLive = true;
} catch (Exception ignored) {}
}
//else L.g().d(TAG, "startCamera: error launching the camera");
}
}
public void stopCamera() {
if (mCamera != null && mIsLive) {
//L.g().d(TAG, "stopCamera");
mCamera.stopPreview();
mCamera.release();
mCamera = null;
mIsPreviewing = false;
mIsLive = false;
}
}
public void startCameraPreview() {
if (mCamera != null && mIsLive && !mIsPreviewing) {
//L.g().d(TAG, "startCameraPreview");
mCamera.setPreviewCallback(this);
mCamera.startPreview();
mIsPreviewing = true;
}
}
public void stopCameraPreview() {
if (mCamera != null && mIsLive && mIsPreviewing) {
//L.g().d("stopCameraPreview");
mCamera.stopPreview();
mIsPreviewing = false;
}
}
}
after a lot of looking last few days I believe that I need to post my solution here.
the only that I have managed to do and it working good is to add a scale.
I wanted to create a textureview with a part of the camera output, but I couldn't do that without letting the preview to get scalled.
so after I decide what is the best resolution for the camera/screen ratio to start capturing I get the scale ratio between the camera capture height and the height I want to show.
mPreviewSize = chooseOptimalSize(...);
int viewHeight = getDP(this, R.dimen.videoCaptureHeight);
float scaleY = mPreviewSize.getHeight() / viewHeight;
setScaleY(scaleY);
Assume you have your Rect or RecF here is your calculation
float imageWidth = bitmap.Width;
float imageHeight = bitmap.Height;
float width = yourscreenWidth;
float heigth = yourscreenHeight ;
var W= width / heigth / (imageWidth / imageHeight);
var W2 = rect.Width() / widt * W;
var H = rect.Height() / heigth;
var cropImageWidth = imageWidth * W2 ;
var cropImageHeight = imageHeight * H ;
var cropImageX = (imageWidth - cropImageWidth) / 2;
var cropImageY = (imageHeight - cropImageHeight) / 2;
Bitmap imageCropped = Bitmap.CreateBitmap(bitmap, (int)cropImageX, (int)cropImageY, (int)cropImageWidth, (int)cropImageHeight);