Xamarin Forms - Xamarin Forms Labs Camera on Page Showing Up - xamarin.forms

Does anyone have an example in Xamarin.Forms of Xamarin.Forms.Labs' Camera function?
I tried to get it working, but it does not seem to work at all.
Here's my code:
public partial class CameraPictureInfoPage : ContentPage
{
public CameraPictureInfoPage ()
{
Image img = new Image ();
this.Appearing += async (s, e) => {
img.Source = await GetPicture (true);
};
this.Content = new StackLayout {
Orientation = StackOrientation.Vertical,
VerticalOptions = LayoutOptions.Center,
WidthRequest = 250,
Padding = 40, Spacing = 10,
Children = {
img
}
};
}
async Task<ImageSource> GetPicture(bool chooseNotTake){
var mediaPicker = DependencyService.Get<IMediaPicker> ();
ImageSource imgSource = null;
if (mediaPicker != null) {
Task<MediaFile> pick;
if (chooseNotTake) {
pick = mediaPicker.TakePhotoAsync (new CameraMediaStorageOptions {
DefaultCamera = CameraDevice.Rear,
MaxPixelDimension = 1024,
});
} else {
pick = mediaPicker.SelectPhotoAsync (new CameraMediaStorageOptions{ MaxPixelDimension = 1024 });
}
await pick.ContinueWith (t => {
if (!t.IsFaulted && !t.IsCanceled) {
var mediaFile = t.Result;
MemoryStream mstr = new MemoryStream ();
mediaFile.Source.CopyTo (mstr);
imgSource = ImageSource.FromStream (() => mstr);
}
return imgSource;
});
}
return imgSource;
}
}

This works for me:
in iOS project in AppDelegate.cs:
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
SetIoc ();
Forms.Init ();
window = new UIWindow (UIScreen.MainScreen.Bounds);
window.RootViewController = App.GetMainPage ().CreateViewController ();
window.MakeKeyAndVisible ();
return true;
}
private void SetIoc ()
{
var resolverContainer = new SimpleContainer ();
resolverContainer.Register<IDevice> (t => AppleDevice.CurrentDevice)
.Register<IDisplay> (t => t.Resolve<IDevice> ().Display)
.Register<IDependencyContainer> (t => resolverContainer);
Resolver.SetResolver (resolverContainer.GetResolver ());
}
In the Forms project:
private async Task<ImageSource> GetPicture(bool chooseNotTake){
var mediaPicker = DependencyService.Get<IMediaPicker> ();
ImageSource imgSource = null;
if (mediaPicker != null) {
Task<MediaFile> pick;
if (!chooseNotTake) {
pick = mediaPicker.TakePhotoAsync (new CameraMediaStorageOptions {
DefaultCamera = CameraDevice.Rear,
MaxPixelDimension = 1024,
});
} else {
pick = mediaPicker.SelectPhotoAsync (new CameraMediaStorageOptions{ MaxPixelDimension = 1024 });
}
await pick.ContinueWith (t => {
if (!t.IsFaulted && !t.IsCanceled) {
var mediaFile = t.Result;
MemoryStream mstr = new MemoryStream();
mediaFile.Source.CopyTo(mstr);
imgSource = ImageSource.FromStream (() => mstr);
}
return imgSource;
}
}
Keep in mind you may need to store the image stream by some other means or it may get garbage-collected prematurely.
To get the picture taker to show up on startup you'll have to avoid async and hook up to Appearing event. In your page's constructor add this:
public class PhotoPage : ContentPage
{
Image img = new Image ();
IMediaPicker picker = null;
Task<MediaFile> task = null;
public PhotoPage ()
{
img.WidthRequest = 60;
img.HeightRequest = 60;
img.BackgroundColor = Color.Silver;
this.Content = new StackLayout {
Orientation = StackOrientation.Vertical,
VerticalOptions = LayoutOptions.Center,
BackgroundColor = Color.Aqua,
WidthRequest = 250,
Padding = 40, Spacing = 10,
Children = {
img,
}
};
this.Appearing += (s, e) => {
picker = DependencyService.Get<IMediaPicker> ();
task = picker.SelectPhotoAsync (new CameraMediaStorageOptions{ MaxPixelDimension = 1024 });
};
Device.StartTimer (TimeSpan.FromMilliseconds (250), () => {
if (task != null) {
if (task.Status == TaskStatus.RanToCompletion) {
Device.BeginInvokeOnMainThread (() => {
img.Source = ImageSource.FromStream (() => task.Result.Source);
});
}
return task.Status != TaskStatus.Canceled
&& task.Status != TaskStatus.Faulted
&& task.Status != TaskStatus.RanToCompletion;
}
return true;
});
}
}

Related

"MultiSelection" not working properly when using "Server Side Filtering" MudBlazor MudTable in Blazor WebAssembly

I started using MudBlazor in a Blazor WebAssembly project.
The problem is that when I use server side filtering and pagination in MudTable, MultiSelection not working properly. I can select all the rows by clicking "Select All" checkbox but selectAll checkbox remains unchecked when All are selected; and unable to unselect all again.
Unselect only working 1 by 1.
I am using this link:
https://try.mudblazor.com/snippet/mEQcYHEKpSAoCWSn
I appreciate your helps.
If you change the code like this it works.
<MudTable ServerData="#(new Func<TableState, Task<TableData<Element>>>(ServerReload))"
#ref="table"
CustomHeader="true"
#bind-SelectedItems="selectedItems1"
MultiSelection="true"
RowClassFunc="#SelectedRowClassFunc"
OnRowClick="RowClickEvent"
RowsPerPageChanged="OnRowsPerPageChanged"
T="Element">
<ToolBarContent>
<MudText Typo="Typo.h6">Periodic Elements</MudText>
<MudSpacer />
<MudTextField T="string" ValueChanged="#(s=>OnSearch(s))" Placeholder="Search" Adornment="Adornment.Start"
AdornmentIcon="#Icons.Material.Filled.Search" IconSize="Size.Medium" Class="mt-0"></MudTextField>
</ToolBarContent>
<HeaderContent>
<MudTHeadRow IgnoreCheckbox="true">
<MudTh>
<MudCheckBox T="bool" Checked="IsSelectAllChecked" CheckedChanged="#Select"></MudCheckBox>
</MudTh>
<MudTh><MudTableSortLabel SortBy="new Func<Element, object>(x=>x.Number)">Nr</MudTableSortLabel></MudTh>
<MudTh>Sign</MudTh>
<MudTh><MudTableSortLabel InitialDirection="SortDirection.Ascending" SortBy="new Func<Element, object>(x=>x.Name)">Name</MudTableSortLabel></MudTh>
<MudTh><MudTableSortLabel SortBy="new Func<Element, object>(x=>x.Position)">Position</MudTableSortLabel></MudTh>
<MudTh><MudTableSortLabel SortBy="new Func<Element, object>(x=>x.Molar)">Mass</MudTableSortLabel></MudTh>
</MudTHeadRow>
</HeaderContent>
<RowTemplate>
<MudTd DataLabel="Nr">#context.Number</MudTd>
<MudTd DataLabel="Sign">#context.Sign</MudTd>
<MudTd DataLabel="Name">#context.Name</MudTd>
<MudTd DataLabel="Position">#context.Position</MudTd>
<MudTd DataLabel="Molar mass">#context.Molar</MudTd>
</RowTemplate>
<NoRecordsContent>
<MudText>No matching records found</MudText>
</NoRecordsContent>
<LoadingContent>
<MudText>Loading...</MudText>
</LoadingContent>
<PagerContent>
<MudTablePager PageSizeOptions="new int[]{1, 5, 10}" />
</PagerContent>
<FooterContent>
<MudTd colspan="5">Select All</MudTd>
</FooterContent>
</MudTable>
<MudText >#($"{selectedItems1.Count} items selected")</MudText>
<MudText Inline="true">Selected items: #(selectedItems1==null ? "" : string.Join(", ", selectedItems1.OrderBy(x=>x.Sign).Select(x=>x.Sign)))</MudText>
#code {
private IEnumerable<Element> pagedData;
private MudTable<Element> table;
private int totalItems;
private string searchString = null;
private List<string> clickedEvents = new();
private HashSet<Element> selectedItems1 = new HashSet<Element>();
private async Task<TableData<Element>> ServerReload(TableState state)
{
IEnumerable<Element> data = await httpClient.GetFromJsonAsync<List<Element>>("webapi/periodictable");
await Task.Delay(300);
data = data.Where(element =>
{
if (string.IsNullOrWhiteSpace(searchString))
return true;
if (element.Sign.Contains(searchString, StringComparison.OrdinalIgnoreCase))
return true;
if (element.Name.Contains(searchString, StringComparison.OrdinalIgnoreCase))
return true;
if ($"{element.Number} {element.Position} {element.Molar}".Contains(searchString))
return true;
return false;
}).ToArray();
totalItems = data.Count();
switch (state.SortLabel)
{
case "nr_field":
data = data.OrderByDirection(state.SortDirection, o => o.Number);
break;
case "sign_field":
data = data.OrderByDirection(state.SortDirection, o => o.Sign);
break;
case "name_field":
data = data.OrderByDirection(state.SortDirection, o => o.Name);
break;
case "position_field":
data = data.OrderByDirection(state.SortDirection, o => o.Position);
break;
case "mass_field":
data = data.OrderByDirection(state.SortDirection, o => o.Molar);
break;
}
pagedData = data.Skip(state.Page * state.PageSize).Take(state.PageSize).ToArray();
return new TableData<Element>() {TotalItems = totalItems, Items = pagedData};
}
private void OnRowsPerPageChanged(int pageSize)
{
selectedItems1.Clear();
}
private void OnSelectedItemsChanged(HashSet<Element> elements)
{
clickedEvents.Add("Selected items changed");
}
private void OnSearch(string text)
{
searchString = text;
table.ReloadServerData();
}
private void RowClickEvent(TableRowClickEventArgs<Element> tableRowClickEventArgs)
{
clickedEvents.Add("Row has been clicked");
}
private string SelectedRowClassFunc(Element element, int rowNumber)
{
return selectedItems1.Contains(element) ? "selected" : string.Empty;
}
private bool IsSelectAllChecked
{
get
{
var currentPage = table.CurrentPage;
var rowsPerPage =table.RowsPerPage;
var currentPageItems = table.FilteredItems.Skip(currentPage * rowsPerPage).Take(rowsPerPage);
if (!selectedItems1.Any(x => currentPageItems.Any(y => x == y)))
{
return false;
}
else
{
return true;
}
}
}
private void Select()
{
var currentPage = table.CurrentPage;
var rowsPerPage = table.RowsPerPage;
var currentPageItems = table.FilteredItems.Skip(currentPage * rowsPerPage).Take(rowsPerPage);
if (!selectedItems1.Any(x => currentPageItems.Any(y => x == y)))
{
foreach(var item in currentPageItems)
{
selectedItems1.Add(item);
}
}
else
{
foreach(var item in currentPageItems)
{
selectedItems1.Remove(item);
}
}
}
}

javascript injected in tinymce editor by wordpress when gutenberg is desactivated

with a fresh install and up to date of wordpress (5.8.2), when I desactivate gutenberg editor, Wordpress add this javascript code in all TinyMCE editor (content, acf fields etc..)
I have no plugin and theme by default. I desactivate Gutenberg with code or with a plugin, no changes. Anyone have a tip ? thx
<script type="text/javascript">
var spector;
var captureOnLoad = false;
var captureOffScreen = false;
window.__SPECTOR_Canvases = [];
(function() {
var __SPECTOR_Origin_EXTENSION_GetContext = HTMLCanvasElement.prototype.getContext;
HTMLCanvasElement.prototype.__SPECTOR_Origin_EXTENSION_GetContext = __SPECTOR_Origin_EXTENSION_GetContext;
if (typeof OffscreenCanvas !== 'undefined') {
var __SPECTOR_Origin_EXTENSION_OffscreenGetContext = OffscreenCanvas.prototype.getContext;
OffscreenCanvas.prototype.__SPECTOR_Origin_EXTENSION_OffscreenGetContext = __SPECTOR_Origin_EXTENSION_OffscreenGetContext;
OffscreenCanvas.prototype.getContext = function () {
var context = null;
if (!arguments.length) {
return context;
}
if (arguments.length === 1) {
context = this.__SPECTOR_Origin_EXTENSION_OffscreenGetContext(arguments[0]);
if (context === null) {
return context;
}
}
else if (arguments.length === 2) {
context = this.__SPECTOR_Origin_EXTENSION_OffscreenGetContext(arguments[0], arguments[1]);
if (context === null) {
return context;
}
}
var contextNames = ["webgl", "experimental-webgl", "webgl2", "experimental-webgl2"];
if (contextNames.indexOf(arguments[0]) !== -1) {
// context.canvas.setAttribute("__spector_context_type", arguments[0]);
// Notify the page a canvas is available.
var myEvent = new CustomEvent("SpectorWebGLCanvasAvailableEvent");
document.dispatchEvent(myEvent);
this.id = "Offscreen";
window.__SPECTOR_Canvases.push(this);
if (captureOnLoad) {
// Ensures canvas is in the dom to capture the one we are currently tracking.
if (false) {
spector.captureContext(context, 500, false, false);
captureOnLoad = false;
}
}
}
return context;
}
}
HTMLCanvasElement.prototype.getContext = function () {
var context = null;
if (!arguments.length) {
return context;
}
if (arguments.length === 1) {
context = this.__SPECTOR_Origin_EXTENSION_GetContext(arguments[0]);
if (context === null) {
return context;
}
}
else if (arguments.length === 2) {
context = this.__SPECTOR_Origin_EXTENSION_GetContext(arguments[0], arguments[1]);
if (context === null) {
return context;
}
}
var contextNames = ["webgl", "experimental-webgl", "webgl2", "experimental-webgl2"];
if (contextNames.indexOf(arguments[0]) !== -1) {
context.canvas.setAttribute("__spector_context_type", arguments[0]);
// Notify the page a canvas is available.
var myEvent = new CustomEvent("SpectorWebGLCanvasAvailableEvent");
document.dispatchEvent(myEvent);
if (captureOffScreen) {
var found = false;
for (var i = 0; i < window.__SPECTOR_Canvases.length; i++) {
if (window.__SPECTOR_Canvases[i] === this) {
found = true;
break;
}
}
if (!found) {
window.__SPECTOR_Canvases.push(this);
}
}
if (captureOnLoad) {
// Ensures canvas is in the dom to capture the one we are currently tracking.
if (this.parentElement || false) {
spector.captureContext(context, 500, false, false);
captureOnLoad = false;
}
}
}
return context;
}
})()</script>
It is very likely added by the Spector.js extension : same behaviour with the Spector extension enabled on Firefox (when switching editor, or after save) => disabling the extension solved the issue.

Implement SelectedItem for CarouselViewControl

Implement SelectedItem(like on ListView) for CarouselViewControl
tried PositionSelected and PositionSelectedCommand Doesn't work as it gives on position of item selected in the list.
ViewModel Implementation:
private void LoadData(IEnumerable<Model> myCourse)
{
this.Items.Clear();
if (myCourse != null)
{
foreach (var item in myCourse)
{
var itemToAdd = new Model
{
ActiviyId = item.ActiviyId,
};
Device.BeginInvokeOnMainThread(() =>
{
this.Items.Add(itemToAdd);
});
}
}
}
public DelegateCommand<Model> CourseSelectedCommand => new DelegateCommand<Model>(async (Param) => await this.OnCourseItemSelectedCommand(Param));
private async Task OnCourseItemSelectedCommand(Model model)
{
var navigationParams = new NavigationParameters();
navigationParams.Add("ActivityID", model.ActiviyId);
await this.navigationService.NavigateAsync("ModulePage", navigationParams, true, false);
}

GWT read mime type client side

I'm trying to read the mime type in GWT client side in order to validate a file before upload it. To do this I use JSNI to read the file header using HTML5 filereader API. However my problem is that GWT does not wait for the result of the reading and continue the code execution. The side effect is that my boolean is not set yet and my condition goes wrong. Is there any mechanism like promise implemented in GWT?
Any help on this would be much appreciated!
UploadImageButtonWidget.java
private boolean isMimeTypeValid = false;
private String mimeType = null;
public native boolean isValid(Element element)/*-{
var widget = this;
var files = element.files;
var reader = new FileReader();
var CountdownLatch = function (limit){
this.limit = limit;
this.count = 0;
this.waitBlock = function (){};
};
CountdownLatch.prototype.countDown = function (){
this.count = this.count + 1;
if(this.limit <= this.count){
return this.waitBlock();
}
};
CountdownLatch.prototype.await = function(callback){
this.waitBlock = callback;
};
var barrier = new CountdownLatch(1);
reader.readAsArrayBuffer(files[0]);
reader.onloadend = function(e) {
var arr = (new Uint8Array(e.target.result)).subarray(0, 4);
var header = "";
for (var i = 0; i < arr.length; i++) {
header += arr[i].toString(16);
}
widget.#com.portal.client.widgets.base.UploadImageButtonWidget::setMimeType(Ljava/lang/String;)(header);
barrier.countDown();
}
return barrier.await(function(){
return widget.#com.portal.client.widgets.base.UploadImageButtonWidget::isMimeTypeValid();
});
}-*/
public void setMimeType(String headerString) {
boolean mimeValid = true;
if (headerString.equalsIgnoreCase(PNG_HEADER)) {
mimeType = PNG_MIMETYPE;
} else if (headerString.equalsIgnoreCase(GIF_HEADER)) {
mimeType = GIF_MIMETYPE;
} else if (headerString.equalsIgnoreCase(JPG_HEADER1) || headerString.equalsIgnoreCase(JPG_HEADER2) || headerString.equalsIgnoreCase(JPG_HEADER3)) {
mimeType = JPG_MIMETYPE;
} else {
mimeValid = false;
setValidationError(i18n.uploadErrorNotImageBasedOnMimeType());
fileChooser.getElement().setPropertyJSO("files", null);
setErrorStatus();
}
setMimeTypeValid(mimeValid);
}
public boolean isMimeTypeValid() {
GWT.log("mimeType" + mimeType);
GWT.log("isMimetypeValid" + String.valueOf(isMimeTypeValid));
return mimeType != null;
}
in the activity:
public void validateAndUpload() {
UploadImageButtonWidget uploadImageButtonWidget = view.getUpload();
if (uploadImageButtonWidget.isValid()) {
GWT.log("mime ok: will be uploaded");
uploadImage();
} else {
GWT.log("mime not ok: will not be uploaded");
}
}

Xamarin Forms - Resize Camera Picture

Someone helped me get this code for taking a picture using xamarin forms labs camera:
picker = DependencyService.Get<IMediaPicker> ();
task = picker.TakePhotoAsync (new CameraMediaStorageOptions {
DefaultCamera = CameraDevice.Rear,
MaxPixelDimension = 800,
});
img.BackgroundColor = Color.Gray;
Device.StartTimer (TimeSpan.FromMilliseconds (250), () => {
if (task != null) {
if (task.Status == TaskStatus.RanToCompletion) {
Device.BeginInvokeOnMainThread (async () => {
//img.Source = ImageSource.FromStream (() => task.Result.Source);
var fileAccess = Resolver.Resolve<IFileAccess> ();
string imageName = "img_user_" + User.CurrentUser().id + "_" + DateTime.Now.ToString ("yy_MM_dd_HH_mm_ss") + ".jpg";
fileName = imageName;
fileAccess.WriteStream (imageName, task.Result.Source);
fileLocation = fileAccess.FullPath(imageName);
FileStream fileStream = new FileStream(fileAccess.FullPath(imageName), FileMode.Open, System.IO.FileAccess.Read);
imageUrl = (string)test[0]["url"];
img.Source = imageUrl;
});
}
return task.Status != TaskStatus.Canceled
&& task.Status != TaskStatus.Faulted
&& task.Status != TaskStatus.RanToCompletion;
}
return true;
});
It saves the image, but the actual size of the phone picture taken is huge, is there a way to resize it.
UPDATE: The original answer is not useful, see below for updated answer. The issue was the PCL library was very slow and consumed too much memory.
ORIGINAL ANSWER (do not use):
I found an image I/O library, ImageTools-PCL, which I forked on github and trimmed down what wouldn't compile in Xamarin, keeping the modifications to minimum and the result seems to work.
To use it download the linked repository, compile it with Xamarin and add the DLLs from Build folder to your Forms project.
To resize an image you can do this (should fit the context of your question)
var decoder = new ImageTools.IO.Jpeg.JpegDecoder ();
ImageTools.ExtendedImage inImage = new ImageTools.ExtendedImage ();
decoder.Decode (inImage, task.Result.Source);
var outImage = ImageTools.ExtendedImage.Resize (inImage, 1024, new ImageTools.Filtering.BilinearResizer ());
var encoder = new ImageTools.IO.Jpeg.JpegEncoder ();
encoder.Encode (outImage, fileAccess.CreateStream (imageName));
ImageSource imgSource = ImageSource.FromFile (fileAccess.FullPath (imageName));
UPDATED ANSWER:
Get Xamarin.XLabs from nuget, learn about using Resolver, create an IImageService interface with Resize method.
Implementation for iOS:
public class ImageServiceIOS: IImageService{
public void ResizeImage(string sourceFile, string targetFile, float maxWidth, float maxHeight)
{
if (File.Exists(sourceFile) && !File.Exists(targetFile))
{
using (UIImage sourceImage = UIImage.FromFile(sourceFile))
{
var sourceSize = sourceImage.Size;
var maxResizeFactor = Math.Min(maxWidth / sourceSize.Width, maxHeight / sourceSize.Height);
if (!Directory.Exists(Path.GetDirectoryName(targetFile)))
Directory.CreateDirectory(Path.GetDirectoryName(targetFile));
if (maxResizeFactor > 0.9)
{
File.Copy(sourceFile, targetFile);
}
else
{
var width = maxResizeFactor * sourceSize.Width;
var height = maxResizeFactor * sourceSize.Height;
UIGraphics.BeginImageContextWithOptions(new CGSize((float)width, (float)height), true, 1.0f);
// UIGraphics.GetCurrentContext().RotateCTM(90 / Math.PI);
sourceImage.Draw(new CGRect(0, 0, (float)width, (float)height));
var resultImage = UIGraphics.GetImageFromCurrentImageContext();
UIGraphics.EndImageContext();
if (targetFile.ToLower().EndsWith("png"))
resultImage.AsPNG().Save(targetFile, true);
else
resultImage.AsJPEG().Save(targetFile, true);
}
}
}
}
}
Implementation of the service for Android:
public class ImageServiceDroid: IImageService{
public void ResizeImage(string sourceFile, string targetFile, float maxWidth, float maxHeight)
{
if (!File.Exists(targetFile) && File.Exists(sourceFile))
{
// First decode with inJustDecodeBounds=true to check dimensions
var options = new BitmapFactory.Options()
{
InJustDecodeBounds = false,
InPurgeable = true,
};
using (var image = BitmapFactory.DecodeFile(sourceFile, options))
{
if (image != null)
{
var sourceSize = new Size((int)image.GetBitmapInfo().Height, (int)image.GetBitmapInfo().Width);
var maxResizeFactor = Math.Min(maxWidth / sourceSize.Width, maxHeight / sourceSize.Height);
string targetDir = System.IO.Path.GetDirectoryName(targetFile);
if (!Directory.Exists(targetDir))
Directory.CreateDirectory(targetDir);
if (maxResizeFactor > 0.9)
{
File.Copy(sourceFile, targetFile);
}
else
{
var width = (int)(maxResizeFactor * sourceSize.Width);
var height = (int)(maxResizeFactor * sourceSize.Height);
using (var bitmapScaled = Bitmap.CreateScaledBitmap(image, height, width, true))
{
using (Stream outStream = File.Create(targetFile))
{
if (targetFile.ToLower().EndsWith("png"))
bitmapScaled.Compress(Bitmap.CompressFormat.Png, 100, outStream);
else
bitmapScaled.Compress(Bitmap.CompressFormat.Jpeg, 95, outStream);
}
bitmapScaled.Recycle();
}
}
image.Recycle();
}
else
Log.E("Image scaling failed: " + sourceFile);
}
}
}
}
#Sten's answer might encounter out-of-memory problem on some android devices. Here's my solution to implement the ResizeImage function
, which is according to google's "Loading Large Bitmaps Efficiently" document:
public void ResizeImage (string sourceFile, string targetFile, int reqWidth, int reqHeight)
{
if (!File.Exists (targetFile) && File.Exists (sourceFile)) {
var downImg = decodeSampledBitmapFromFile (sourceFile, reqWidth, reqHeight);
using (var outStream = File.Create (targetFile)) {
if (targetFile.ToLower ().EndsWith ("png"))
downImg.Compress (Bitmap.CompressFormat.Png, 100, outStream);
else
downImg.Compress (Bitmap.CompressFormat.Jpeg, 95, outStream);
}
downImg.Recycle();
}
}
public static Bitmap decodeSampledBitmapFromFile (string path, int reqWidth, int reqHeight)
{
// First decode with inJustDecodeBounds=true to check dimensions
var options = new BitmapFactory.Options ();
options.InJustDecodeBounds = true;
BitmapFactory.DecodeFile (path, options);
// Calculate inSampleSize
options.InSampleSize = calculateInSampleSize (options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.InJustDecodeBounds = false;
return BitmapFactory.DecodeFile (path, options);
}
public static int calculateInSampleSize (BitmapFactory.Options options, int reqWidth, int reqHeight)
{
// Raw height and width of image
int height = options.OutHeight;
int width = options.OutWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
int halfHeight = height / 2;
int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
You can do this natively for each platform and use an interface. Heres an example for IOS
In your PCL project you need to add an interface
public interface IImageResizer
{
byte[] ResizeImage (byte[] imageData, double width, double height);
}
Then to resize an image in your code, you can load the IOS implementation of that interface using the DependencyService and run the ResizeImage method
var resizer = DependencyService.Get<IImageResizer>();
var resizedBytes = resizer.ResizeImage (originalImageByteArray, 400, 400);
Stream stream = new MemoryStream(resizedBytes);
image.Source = ImageSource.FromStream(stream);
IOS Implementation, add this class to your IOS project.
[assembly: Xamarin.Forms.Dependency (typeof (ImageResizer_iOS))]
namespace YourNamespace
{
public class ImageResizer_iOS : IImageResizer
{
public byte[] ResizeImage (byte[] imageData, double maxWidth, double maxHeight)
{
UIImage originalImage = ImageFromByteArray (imageData);
double width = 300, height = 300;
double maxAspect = (double)maxWidth / (double)maxHeight;
double aspect = (double)originalImage.Size.Width/(double)originalImage.Size.Height;
if (maxAspect > aspect && originalImage.Size.Width > maxWidth) {
//Width is the bigger dimension relative to max bounds
width = maxWidth;
height = maxWidth / aspect;
}else if (maxAspect <= aspect && originalImage.Size.Height > maxHeight){
//Height is the bigger dimension
height = maxHeight;
width = maxHeight * aspect;
}
return originalImage.Scale(new SizeF((float)width,(float)height)).AsJPEG ().ToArray ();
}
public static MonoTouch.UIKit.UIImage ImageFromByteArray(byte[] data)
{
if (data == null) {
return null;
}
MonoTouch.UIKit.UIImage image;
try {
image = new MonoTouch.UIKit.UIImage(MonoTouch.Foundation.NSData.FromArray(data));
} catch (Exception e) {
Console.WriteLine ("Image load failed: " + e.Message);
return null;
}
return image;
}
}
}
An update from the Xamarin Media Plugin allows you to resize the image
https://github.com/jamesmontemagno/MediaPlugin
... barring that, and you need a more generic resize option (say the image comes from a web call, and not the device, then have a look at:
https://github.com/InquisitorJax/Wibci.Xamarin.Images

Resources