I am using ImageCropper and MediaPlugin to Upload images. However I have problem getting the image after cropping the image.
string imagefile;
protected void OnClickedRectangle(object sender, EventArgs e)
{
new ImageCropper()
{
Success = (imageFile) =>
{
Device.BeginInvokeOnMainThread(() =>
{
view_imageavatar.Source = ImageSource.FromFile(imageFile);
});
}
}.Show(this);
}
async void edit_avatar_Tapped(object sender, EventArgs e)
{
try
{
await CrossMedia.Current.Initialize();
new ImageCropper()
{
PageTitle = "Title",
AspectRatioX = 1,
AspectRatioY = 1,
CropShape = ImageCropper.CropShapeType.Rectangle,
SelectSourceTitle = "Img",
TakePhotoTitle = "Take Camera",
PhotoLibraryTitle = "Img Gallery",
Success = (imageFile) =>
{
Device.BeginInvokeOnMainThread(async() =>
{
view_imageavatar.Source = ImageSource.FromFile(imageFile);
imagefile = imageFile;
//API Get Images Upload
var content = new MultipartFormDataContent();
content.Add(new StreamContent(imageFile), "files", imagefile);
var httpClient = new HttpClient();
var responses = await httpClient.PostAsync("https://xxxxx/api/Upload", content);
});
}
}.Show(this);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine("GalleryException:>" + ex);
}
}
However how can I get the Image to upload. note that view_imageavatar still shows the image after cropping. Tks!
Update...
async void edit_avatar_Tapped(object sender, EventArgs e)
{
try
{
await CrossMedia.Current.Initialize();
new ImageCropper()
{
PageTitle = "Title",
AspectRatioX = 1,
AspectRatioY = 1,
CropShape = ImageCropper.CropShapeType.Rectangle,
SelectSourceTitle = "Img",
TakePhotoTitle = "Take Camera",
PhotoLibraryTitle = "Img Gallery",
Success = (imageFile) =>
{
Device.BeginInvokeOnMainThread(async() =>
{
view_imageavatar.Source = ImageSource.FromFile(imageFile);
imagefile = imageFile;
//API Get Images Upload
var fileStream = File.OpenRead(imageFile);
var fileContent = new StreamContent(fileStream);
var content = new MultipartFormDataContent();
content.Add(fileContent, "files", imageFile);
var httpClient = new HttpClient();
var responses = await httpClient.PostAsync("https://xxxxxx/api/UploadAvatarUs", content);
});
}
}.Show(this);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine("GalleryException:>" + ex);
}
}
It still doesn't work?
Update 2
async void edit_avatar_Tapped(object sender, EventArgs e)
{
try
{
await CrossMedia.Current.Initialize();
new ImageCropper()
{
PageTitle = "Title",
AspectRatioX = 1,
AspectRatioY = 1,
CropShape = ImageCropper.CropShapeType.Rectangle,
SelectSourceTitle = "Img",
TakePhotoTitle = "Take Camera",
PhotoLibraryTitle = "Img Gallery",
Success = (imageFile) =>
{
Device.BeginInvokeOnMainThread(async() =>
{
view_imageavatar.Source = ImageSource.FromFile(imageFile);
imagefile = imageFile;
//API Get Images Upload
var upfilebytes = File.ReadAllBytes(imageFile);
var ms = new MemoryStream(upfilebytes);
var content = new MultipartFormDataContent();
content.Add(new StreamContent(ms), "files", imageFile);
var httpClient = new HttpClient();
var responses = await httpClient.PostAsync("https://xxxxxx/api/UploadAvatarUs", content);
});
}
}.Show(this);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine("GalleryException:>" + ex);
}
}
-> It still can't upload photos through the API?
However I try not to use ImageCropper. I upload directly.
async void edit_avatar_Tapped(object sender, EventArgs e)
{
var file = await MediaPicker.PickPhotoAsync();
var content = new MultipartFormDataContent();
content.Add(new StreamContent(await file.OpenReadAsync()), "files", file.FileName);
var httpClient = new HttpClient();
var responses = await httpClient.PostAsync("https://xxxxxx/api/UploadAvatarUs", content);
string a = responses.StatusCode.ToString();
}
--> Then it works fine, the image is uploaded through the API
Does the image load from content.Add(new StreamContent(ms), "files", imageFile); it doesn't work with API? Looking for solutions from everyone.
Have you actually checked what StreamContent takes as arguments?
It takes a Stream not a path to a file.
You need to open the file first like so:
using var fileStream = File.Open(imageFile);
using var fileContent = new StreamContent(fileStream);
Have you tried something like that?
Related
Here is the code that works but it doesn't wait until the completion. How do I make sure the file has been saved?
var browser = await Puppeteer.LaunchAsync(new LaunchOptions
{
ExecutablePath = "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe",
Headless = false,
});
var page = (await browser.PagesAsync()).First();
page.Response += async (object sender, ResponseCreatedEventArgs e) =>
{
if (e.Response.Url.Contains(".mp4"))
{
byte[] buff = await e.Response.BufferAsync();
File.WriteAllBytes($"{DateTime.UtcNow.ToFileTime()}.mp4", buff);
}
};
await page.GoToAsync("https://file-examples-com.github.io/uploads/2017/04/file_example_MP4_480_1_5MG.mp4");
await Task.Delay(30000);
Here, just wrote it:
public static async Task<FileInfo> DownloadFileAsync(string url)
{
try
{
await _page.GoToAsync(url);
}
catch (NavigationException)
{
// Trying to open a file page throws navigation exception, should be ignored
}
await _page.WaitForNetworkIdleAsync();
while (Directory.GetFiles(_downloadDirectory, "*.crdownload", SearchOption.AllDirectories).Length > 0)
{
await Task.Delay(250);
}
for (int i = 0; i < 100; i++)
{
var finishedFiles = (new DirectoryInfo(_downloadDirectory)).GetFiles();
var downloadedFile = finishedFiles.OrderByDescending(f => f.LastWriteTime).FirstOrDefault();
if (downloadedFile != null)
{
return downloadedFile!;
}
await Task.Delay(250);
}
throw new Exception($"Download failed for: {url}");
}
I'm trying to use the Azure OCR API in Xamarin Forms. Here is the important bits of code. I'm using the ComputerVisionClient .net client
await CrossMedia.Current.Initialize();
if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported)
{
return;
}
var file = await CrossMedia.Current.TakePhotoAsync(new StoreCameraMediaOptions
{
SaveToAlbum = false
});
Img = new Image
{
Source = ImageSource.FromStream(() =>
{
var stream = file.GetStream();
return stream;
}),
};
using (var photoStream = file.GetStream())
{
var text = await _client.RecognizePrintedTextInStreamAsync(true, photoStream);
}
The Img is bound to an image on the view and it shows up when I take a picture so there is definetly an image. However RecognizePrintedTextInStreamAsync returns back "System.IO.FileNotFoundException: 'Invalid Image'" and I'm not sure why. Any ideas?
Edit. Added _client code
public static ComputerVisionClient Authenticate(string endpoint, string key)
{
ComputerVisionClient client =
new ComputerVisionClient(new ApiKeyServiceClientCredentials(key))
{ Endpoint = endpoint };
return client;
}
Called from my constructor and set as a global var
_client = Authenticate(endpoint, subscriptionKey);
Thanks
I am trying to capture an image/pick up an image from gallery in Xamarin Forms app. I have installed the nuget manager > Birdie.MediaPlugin. During On click on the button in the Register page throws below error;
Plugin.Media.Abstractions.MediaPermissionException: <Timeout exceeded getting exception details Could someone please advise where should we add persmission in Xamarin.Forms app ?
// Register.xaml:
<Image x:Name="imageDisplay" />
<Button x:Name="uploadButton"
Text="Upload Image" Clicked="UploadButton_Clicked"/>
// PlayerDetails.cs
public ImageSource Source { get; internal set; }
//Register.xaml.cs
PlayerDetails myDetails;
public Register(PlayerDetails playD)
{
InitializeComponent();
BindingContext = myDetails;
}
private async void UploadButton_Clicked(object sender, EventArgs e)
{
//myDetails.Image = new Image();
if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported)
{
await DisplayAlert("No Camera", ":( No camera avaialble.", "OK");
return;
}
var status = await GetPermissions();
if(status == true)
{
var file = await CrossMedia.Current.TakePhotoAsync(new StoreCameraMediaOptions
{
Directory = "Sample",
Name = "flower1.jpg"
});
if (file == null)
return;
await DisplayAlert("File Location", file.Path, "OK");
myDetails.Source = ImageSource.FromStream(() =>
{
var stream = file.GetStream();
file.Dispose();
return stream;
});
}
else
{
await DisplayAlert("Permissions Denied", "Unable to take photos.", "OK");
//On iOS you may want to send your user to the settings screen.
if (Device.RuntimePlatform == Device.iOS)
CrossPermissions.Current.OpenAppSettings();
}
}
//I have split the permission function as below;
public static async Task<bool> GetPermissions()
{
bool permissionsGranted = true;
var permissionsStartList = new List<Permission>()
{
Permission.Location,
Permission.LocationAlways,
Permission.LocationWhenInUse,
Permission.Storage,
Permission.Camera
};
var permissionsNeededList = new List<Permission>();
try
{
foreach (var permission in permissionsStartList)
{
var status = await CrossPermissions.Current.CheckPermissionStatusAsync(permission);
if (status != PermissionStatus.Granted)
{
permissionsNeededList.Add(permission);
}
}
}
catch (Exception ex)
{
Console.WriteLine("Nice, exception! " + ex);
}
var results = await CrossPermissions.Current.RequestPermissionsAsync(permissionsNeededList.ToArray());
try
{
foreach (var permission in permissionsNeededList)
{
var status = PermissionStatus.Unknown;
//Best practice to always check that the key exists
if (results.ContainsKey(permission))
status = results[permission];
if (status == PermissionStatus.Granted || status == PermissionStatus.Unknown)
{
permissionsGranted = true;
}
else
{
permissionsGranted = false;
break;
}
}
}
catch (Exception ex)
{
Console.WriteLine("Last, exception! " + ex);
}
return permissionsGranted;
}
You can update your OnClick event code to add the permissions logic as well:
var cameraStatus = await CrossPermissions.Current.CheckPermissionStatusAsync<CameraPermission>();
var storageStatus = await CrossPermissions.Current.CheckPermissionStatusAsync<StoragePermission>();
if (cameraStatus != PermissionStatus.Granted || storageStatus != PermissionStatus.Granted)
{
cameraStatus = await CrossPermissions.Current.RequestPermissionAsync<CameraPermission>();
storageStatus = await CrossPermissions.Current.RequestPermissionAsync<StoragePermission>();
}
if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported)
{
await DisplayAlert("No Camera", ":( No camera avaialble.", "OK");
return;
}
if (cameraStatus == PermissionStatus.Granted && storageStatus == PermissionStatus.Granted)
{
var file = await CrossMedia.Current.TakePhotoAsync(new StoreCameraMediaOptions
{
Directory = "Sample",
Name = "flower1.jpg"
});
if (file == null)
return;
await DisplayAlert("File Location", file.Path, "OK");
myDetails.Source = ImageSource.FromStream(() =>
{
var stream = file.GetStream();
file.Dispose();
return stream;
});
}
else
{
await DisplayAlert("Permissions Denied", "Unable to take photos.", "OK");
//On iOS you may want to send your user to the settings screen.
if (Device.RuntimePlatform == Device.iOS)
CrossPermissions.Current.OpenAppSettings();
}
Note:It will become a long function so I recommend breaking it up into different functions.
I am getting an image stream from TakePhotoAsync Method? Where do I need to change the code?
await CrossMedia.Current.Initialize();
if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported)
{
await DisplayAlert("Alert", "No camera is available!", "OK");
return;
}
camreaFile = await CrossMedia.Current.TakePhotoAsync(new StoreCameraMediaOptions
{
PhotoSize = Plugin.Media.Abstractions.PhotoSize.Small,
//SaveToAlbum = true,
Directory = "Sample",
Name = "test.jpg"
});
//mediaFile = await CrossMedia.Current.TakePhotoAsync();
if (camreaFile == null)
return;
fileName.Text = camreaFile.AlbumPath;
await DisplayAlert("File Location", camreaFile.Path, "OK");
image.Source = ImageSource.FromStream(() =>
{
var stream = camreaFile.GetStream();
//camreaFile.Dispose();
return stream;
});
--Pass parameter for server
if(mediaFile !=null)
{
MultipartFormDataContent content = new
MultipartFormDataContent();
content.Add(new StringContent(AppSetting.UserName),
"userId");
content.Add(new StringContent(remark), "remarks");
content.Add(new StringContent(AppSetting.ConsignmentNumebr), "consignmentNo");
content.Add(new StringContent(AppSetting.TaskId), "jobId");
content.Add(new StreamContent(cameraFile.GetStream()),"\"file\"",$"\"{AppSetting.ConsignmentNumebr + ".png"}\"");
var httpClient = new HttpClient();
var uploadServiceBaseAddress = "myserver/api/UploadContainerImage/"; var uploadResponseMessage = await httpClient.PostAsync(uploadServiceBaseAddress, content);uploadResponseMessage.Content.ReadAsStringAsync(); }
--I expect the output that successfully reaches the server.
Dispose of the Media file after you send it to the server to avoid this exception.
If you do that before you are sending it to the server, of course, it will give you an ObjectDisposedException
If you want to dispose of this variable just do it after the service call something like below:
FooServiceMethod();
mediaFile.Dispose();
I encounter a problem that when upload file size large than 100kb, web api controller will not be called. I search for a while and found that maybe I should set maxRequestLength in webconfig. But how to set it in self host?
the client
public async Task<bool> Upload(DeviceFile file,string path)
{
var formData = new MultipartFormDataContent();
var request = new HttpRequestMessage();
var md5 = new MD5CryptoServiceProvider();
var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read,bufferSize:4096,useAsync:true);
fileStream.Position = 0;
var hash = md5.ComputeHash(fileStream);
fileStream.Position = 0;
formData.Add(
new StreamContent(fileStream),
file.Name,
file.Name,
new {
Info = file.Info,
}
);
request.Method = HttpMethod.Post;
request.Content = formData;
request.RequestUri = new Uri(client.BaseAddress,"api/file/");
try
{
var response = await client.SendAsync(request).ConfigureAwait(false);
await response.Content.ReadAsAsync<bool>().ConfigureAwait(false);
}
catch (Exception ex)
{
this.logger.Log(ex.ToString(), Category.Info, Priority.None);
}
return true;
}
the server controller
public async Task<HttpResponseMessage> Add()
{
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
var provider = new MultipartFormDataStreamProvider("D:/");
try
{
await Request.Content.ReadAsMultipartAsync(provider);
// This illustrates how to get the file names.
foreach (MultipartFileData file in provider.FileData)
{
Console.WriteLine(file.Headers.ContentDisposition.FileName);
Console.WriteLine("Server file path: " + file.LocalFileName);
}
foreach (var key in provider.FormData.AllKeys)
{
foreach (var val in provider.FormData.GetValues(key))
{
Console.WriteLine(string.Format("{0}: {1}", key, val));
}
}
return Request.CreateResponse(HttpStatusCode.OK);
}
catch (System.Exception e)
{
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e);
}
}
The MaxReceivedMessageSize can be set on the self-host config object.
http://msdn.microsoft.com/en-us/library/system.web.http.selfhost.httpselfhostconfiguration.maxreceivedmessagesize(v=vs.108).aspx#feedback