Xamarin Forms - capturing photo from camera (Android) - forms

A callback for the camera never gets invoked when I take a photo. It only gets invoked when I select existing photo from a gallery.
MessagingCenter.Subscribe<byte[]>(this, "ImageSelected", (args) =>
{
Device.BeginInvokeOnMainThread(() =>
{
//Set the source of the image view with the byte array <<== NEVER INVOKED
Image img = new Image();
MemoryStream stream = new MemoryStream((byte[])args);
//img.Source = ImageSource.FromStream(() => new MemoryStream((byte[])args));
imagePallet.Source = ImageSource.FromStream(() => { return stream; });
imagePreview.IsVisible = true;
});
});
I am using the setup outlined here:
https://baglabs.com/2017/01/12/xamarin-forms-using-camera-photo-gallery/
I noticed the OnActivityResult executes in MainActivity.cs but the Data property of Intent is always null when select photo taken from camera, it's only set when selecting photo from gallery as before.
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
//Since we set the request code to 1 for both the camera and photo gallery, that's what we need to check for
if (requestCode == 1)
{
if (resultCode == Result.Ok)
{
if (data.Data != null) --<<==ALWAYS NULL WHEN ACCEPTING PHOTO TAKEN WITH CAMERA
{
//Grab the Uri which is holding the path to the image
Android.Net.Uri uri = data.Data;
//Read the meta data of the image to determine what orientation the image should be in
int orientation = getOrientation(uri);
//Stat a background task so we can do all the bitmap stuff off the UI thread
BitmapWorkerTask task = new BitmapWorkerTask(this.ContentResolver, uri);
task.Execute(orientation);
}
}
}
Clearly I am missing something. Many thanks!

Related

Image not displaying in .NET MAUI Mac Catalyst

I'm trying to display an image to make my own custom splash screen using .NET MAUI. It is made in C# and does not use XAML. Here is my code:
SplashScreenActivity.cs:
using System;
using System.Text;
namespace LiveEditorHTML
{
public partial class SplashScreenActivity : ContentPage
{
Image splashScreenImage;
public async Task<string> ShowMsg(string title,
string msg, bool isQuestion, bool isInput,
int? num, string[]? question)
{
bool answer;
if (isQuestion && !isInput)
{
answer = await DisplayAlert(title, msg, "Yes", "No");
return answer.ToString();
}
else if (!isQuestion && !isInput)
{
await DisplayAlert(title, msg, "OK");
}
else if (!isQuestion && isInput)
{
string action = await DisplayActionSheet(
title + msg, "Cancel",
null, question
);
}
else
{
await DisplayAlert(title, msg, "OK");
}
return null;
}
public SplashScreenActivity()
{
var uiView = new ScrollView();
var stackLayout = new VerticalStackLayout();
var img = AssetsHelper.LoadMauiAsset("logo.png").Result;
Task.Run(() =>
{
string output = ShowMsg("Debug", img, false, false, 0, null).Result;
});
byte[] byteArray = Encoding.UTF8.GetBytes(img);
MemoryStream stream = new MemoryStream(byteArray);
splashScreenImage = new Image()
{
Source = ImageSource.FromStream(() => stream)
};
stackLayout.Children.Add(splashScreenImage);
this.Content = uiView;
}
}
}
AssetsHelper.cs:
using System;
namespace LiveEditorHTML
{
public class AssetsHelper
{
public static async Task<string> LoadMauiAsset(string fileName)
{
using var stream = await FileSystem.OpenAppPackageFileAsync(fileName);
using var reader = new StreamReader(stream);
var contents = reader.ReadToEndAsync();
return contents.Result;
}
}
}
Here is the image I used, created with GIMP, the image size is 456x456 (the same as the image sizes of the appicon.svg and appiconfg.svg files located at: Resources\AppIcon):
The ShowMsg() function is used to create a MessageBox like C# Winforms, in addition, it is also used for the cases of creating a Yes No questionnaire, and creating a questionnaire that requires the user to enter text. Currently, I just use the simplest feature, like the MessageBox in C# Winforms, which is to print a debug message, with the title Debug and the content as an image file that is read with the help of the AssetsHelper.cs support class.
When I run the program, the Debug window for printing information pops up, indicating that it is working, the file logo.png (with path at Resources\Raw) has been read successfully:
But then nothing is displayed:
I highly suspected that there might be an error, but no exceptions occurred, so I used the built-in image: dotnet_bot.svg to test (link at: Resources\Images). I replaced the following line in SplashScreenActivity.cs:
ImageSource.FromStream(() => stream)
Fort:
"dotnet_bot.svg"
The code becomes:
splashScreenImage = new Image()
{
Source = "dotnet_bot.svg"
};
to test. When I turn on the app and go through the Debug screen (since I haven't dropped the code that shows the Debug dialog), they don't work either:
And no exception is thrown. The app doesn't crash either.
All versions of .NET MAUI and VS are updated and VS is the latest Preview version. The computer I'm using is a Macbook Pro running macOS Monterey 12.5.1
So what's going on?
I had create a sample to test your code and the image can't show either. I found that you have changed the image file to the string, and then changed the string to the byte array.
You can try to convert the image to the byte array or set the image as the source directly. In addition, you didn't add the stacklayout into the scrollview. So you should add it or set the stacklayout as the page.content.
Set the image as the source directly
splashScreenImage = new Image()
{
Source = "test" // the test.png is in the /Resource/Image folder
};
stackLayout.Children.Add(splashScreenImage);
this.Content = stackLayout;
2.Convert the image to the byte array directly
public static async Task<byte[]> LoadMauiAsset(string fileName)
{
using var stream = await FileSystem.OpenAppPackageFileAsync(fileName);
byte[] buffer = new byte[stream.Length];
stream.Read(buffer, 0, buffer.Length);
return buffer;
}
MemoryStream stream = new MemoryStream(AssetsHelper.LoadMauiAsset("test").Result);
splashScreenImage = new Image()
{
Source = ImageSource.FromStream(() => stream)
};
stackLayout.Children.Add(splashScreenImage);
this.Content = stackLayout;

How to give a user the option to select bsckground of a linearlayout from DxsettingsActivity that targets the MainActivity?

I want the user to be able to go into settings of my app and select from the images provided or select a photo from their internal or external storage to be applied to the background of the MainActivity. Also I want this image to stay even after the app has been killed until the user decides to change the background again. I have tried multiple codes and I run into errors every time and the main problem I'm having is sending this intent from one Activity to another. I have used code that allow me to apply an image to an ImageView within the same Activity but I cannot take that code and get it to send across to another Activity.
Targets:
LinearLayout - backgroundtop (MainActivity)
Imageview(onClick) - gallery (DxsettingsActivity)
Imageview(onClick) - dx (DxsettingsActivity)
"Gallery" and "dx" are in a customview dialog.
When "gallery" is clicked internal/external storage is opened to select background resource of "backgroundtop" and save that image until user changes it again.
When "dx" is clicked it opens DxWallpaperActivity which will have the images to be selected and saved as the background of "backgroundtop".
I hope I have explain well enough. I'll provide more info if needed. Thank you in advance. I have been struggling with this for days to no avail.
Update: I have managed to accomplish setting and saving images from in-app images to the background. I have tried everything under the sun to pull image from gallery and do the same. I have managed to open gallery and select an image but I can't figure out onActivityResult then send that to the background. Please help.
This is the only code I've got to work but it doesn't have shared preferences and it for an imageview. How can I change it for backgroundresource on linearlayout?
}
private static final String STATE_IMAGE_URI =
"STATE_IMAGE_URI";
private Uri imageUri;
public void onSaveInstanceState(Bundle state) {
super.onSaveInstanceState(state);
if (imageUri != null ) {
state.putParcelable(STATE_IMAGE_URI, imageUri);
}
}
public void onRestoreInstanceState(Bundle state) {
super.onRestoreInstanceState(state);
if(state == null || !state.containsKey(STATE_IMAGE_URI))
return;
setImage((Uri) state.getParcelable(STATE_IMAGE_URI));
}
private static final int IMAGE_REQUEST_CODE = 9;
private void chooseImage() {
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent,
"Select picture"), IMAGE_REQUEST_CODE);
}
public void onActivityResult(int requestCode, int.
resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode != IMAGE_REQUEST_CODE) {
return;
}
if (resultCode != Activity.RESULT_OK) {
return;
}
setImage(data.getData());
}
private void setImage(Uri uri) {
imageUri = uri;
imageview1.setImageURI(uri);
}
private void nothing() {
And for the button clicked
chooseImage();

Camera intent causes very low quality of picture in preview [duplicate]

This question already has answers here:
Low picture/image quality when capture from camera
(3 answers)
Closed 3 years ago.
I have an Android app which opens the camera to take a pic:
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, PICTURE_RESULT);
If it is called the camera is opened and I can take picture. But the preview where to click OK or Cancel is already very bad quality.
This is strange as this is not implemented by my app. Are there any parameters to configure for the camera intent to increase the quality.
This example im uploading to firebase:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == GALLERY_INTENT && resultCode == RESULT_OK){
Uri uri = data.getData();
progressDialog.setMessage(UPLOADING);
progressDialog.show();
StorageReference filePath = storageRef.child(STORAGE_FOLDER_NAME).child(recipeTitle.getText().toString());
filePath.putFile(uri).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
#Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
Toast.makeText(CreateNewRecipeActivity.this, UPLOAD_COMPLETE, Toast.LENGTH_SHORT).show();
progressDialog.dismiss();
}
});
}
}
Here im getting the full image
Uri uri = data.getData();

onActivityResult() not getting executed in DialogFragment

I have been looking in thousand posts for this, but I do not find how to solve my problem.
I have an ImageView. When the user clicks on this ImageView, a DialogFragment is displayed, and the user can choose between taking a new picture with the camera, or selecting a picture from the gallery. Until here everything works fine.
The problem is, that the picture selected by the user, should replace the current one in the ImageView, but this bit, is the one that is not working, because the onActivityResult() function that executes this code is not being executed, so the image in the ImageView always remains the same. I would appreciate any help, because I do not see or understand, why this code is not being executed.
I am getting a warning in the LogCat right after the user selects the image:
05-07 12:17:11.542: I/ActivityManager(59): Displayed activity com.android.gallery/com.android.camera.ImageGallery: 935 ms (total 935 ms)
05-07 12:17:12.812: W/FragmentActivity(3614): Activity result no fragment exists for index: 0x10001
05-07 12:17:12.862: W/InputManagerService(59): Starting input on non-focused client com.android.internal.view.IInputMethodClient$Stub$Proxy#45fd9c38 (uid=10016 pid=317)
Activity.java:
private ImageView imageLoader = null;
imageLoader = (ImageView) findViewById(R.id.f_imageLoader);
imageLoader.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
ImageLoaderDialog imageLoaderDialog = new ImageLoaderDialog(imageLoader);
imageLoaderDialog.show(getSupportFragmentManager(), "imageLoaderDialog");
}
Activity.xml:
<ImageView
android:id="#+id/f_imageLoader"
android:layout_width="wrap_content"
android:layout_height="0dip"
android:layout_weight="0.20"
android:contentDescription="#string/imgDesc"
android:src="#drawable/my_image" />
ImageLoaderDialog.java:
//Dialog for choosing between new camera image or gallery image.
public class ImageLoaderDialog extends android.support.v4.app.DialogFragment {
private ImageView targetImageView = null;
final int TAKE_PICTURE = 0;
final int PICK_PHOTO = 1;
public ImageLoaderDialog (View view) {
targetImageView = (ImageView) view;
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle("Selecciona");
final String[] imageSources = getResources().getStringArray(R.array.imageSources);
builder.setItems(imageSources, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int item) {
switch(item) {
case TAKE_PICTURE:
Intent takePicture = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(takePicture, TAKE_PICTURE);
break;
case PICK_PHOTO:
Intent pickPhoto = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(pickPhoto, PICK_PHOTO);
break;
}
}
});
return builder.create();
}
//Set image to user's selected image.
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
if (resultCode == android.app.Activity.RESULT_OK) {
Uri selectedImage = intent.getData();
Log.i("IMAGEN", ""+selectedImage);
targetImageView.setImageURI(selectedImage);
}
}
}
Any help would be very appreciated.
The hosting activity overrode the onActivityResult but did not make a call to super.onActivityResult for unhandled result codes. Apparently even though the fragment is the one making the startActivityForResult call, the activity gets the first shot at handling the result. This makes sense when you consider the modularity of fragments. Once I implemented super.onActivityResult for all unhandled results, the fragment got a shot at handling the result.Try This:
getActivity().onActivityResult(requestCode, resultCode, intent);

How can i repeat same activity after user has chosen right option?

ImageView Iv2 = (ImageView)findViewById(R.id.imageView2);
textId++;
String imgId = "full_" + textId;
int Ivid = getResources().getIdentifier(imgId, "drawable", getPackageName());
Iv2.setImageResource(Ivid);
Iv2.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
clapping = MediaPlayer.create(textBasedquiz.this, R.raw.applause);
clapping.start();
Intent intent = getIntent();
overridePendingTransition(0, 0);
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
finish();
overridePendingTransition(0, 0);
startActivity(intent);
return true;
}
});
*Basically im trying to build an quiz for kids and in this im selecting images randomly i want to restart same code after user has touch on right image so he/she can get another question , but activity must start after sound has been played Please Guys help me i really need your valued comments *
You can setResult and go to activity from where you have called your this activity. Pass the value along and based on result of value received, call the saem activity passing new value that you just got from the same activity.
static int RESULT_OK = 100;
STATIC INT RESULT_CANCEL = 110;
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch(resultCode) {
case RESULT_OK:
// Get flags/values from intent Intent.FLAG_ACTIVITY_NO_ANIMATION
// Create new activity setting the intent to call
// and pass the values
startActivity(intent);
break;
}
}
I think this will be more straight forward rather than calling same Activity from itself only.