I'm developing a Xamarin Forms iOS app. In the xaml file, there is a grid.
<Grid x:Name="QrCodeSite" HeightRequest="300" Margin="37, 37, 37, 0">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
</Grid>
In the related .cs file, I use ZXing.Net.Mobile.Forms to generate a QR code and place it in the grid. And I put my logo in the same grid, which will finally appear at the center of the QR code.
var barcode = new ZXingBarcodeImageView
{
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand
};
barcode.BarcodeFormat = ZXing.BarcodeFormat.QR_CODE;
barcode.BarcodeOptions.Width = 650;
barcode.BarcodeOptions.Height = 650;
barcode.BarcodeOptions.Margin = 1;
barcode.BarcodeValue = value;
var img = new Image
{
Source = "logo.png",
WidthRequest = 70,
HeightRequest = 70,
VerticalOptions = LayoutOptions.Center,
HorizontalOptions = LayoutOptions.Center
};
QrCodeSite.Children.Clear();
QrCodeSite.Children.Add(barcode);
QrCodeSite.Children.Add(img);
The problem is, maybe my phone (iPhone 6s plus) is too slow, sometimes the logo appears first and after a lag (around 1 second) the QR code is shown. How can I merge the QR code and the logo into one image and then add it to the grid?
You can using SkiaSharp to display Image or merge images . Having a look at how to Display SkiaSharp bitmaps to download sample project to research at it.
Based on Drawing on existing bitmaps reference , you can modify it as follow :
public partial class MonkeyMoustachePage : ContentPage
{
SKBitmap monkeyBitmap;
public MonkeyMoustachePage()
{
Title = "Monkey Moustache";
monkeyBitmap = BitmapExtensions.LoadBitmapResource(GetType(),
"SkiaSharpFormsDemos.Media.MonkeyFace.png");
SKBitmap iconImage = BitmapExtensions.LoadBitmapResource(GetType(),
"SkiaSharpFormsDemos.Media.GooglePlaylogo.png");
int offset = monkeyBitmap.Width / 2 - iconImage.Width / 2;
int offsetTop = monkeyBitmap.Height / 2 - iconImage.Height / 2;
// Create canvas based on bitmap
using (SKCanvas canvas = new SKCanvas(monkeyBitmap))
{
canvas.DrawBitmap(iconImage, SKRect.Create(offset, offsetTop, iconImage.Width, iconImage.Height));
}
// Create SKCanvasView to view result
SKCanvasView canvasView = new SKCanvasView();
canvasView.PaintSurface += OnCanvasViewPaintSurface;
Content = canvasView;
//save the new image
using (MemoryStream memStream = new MemoryStream())
using (SKManagedWStream wstream = new SKManagedWStream(memStream))
{
monkeyBitmap.Encode(wstream, imageFormat, quality);
byte[] data = memStream.ToArray();
// Check the data array for content!
bool success = await DependencyService.Get<IPhotoLibrary>().SavePhotoAsync(data, folder, filename);
// Check return value for success!
}
}
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
canvas.DrawBitmap(monkeyBitmap, info.Rect, BitmapStretch.Uniform);
}
}
Then you will see a logo icon will display in original image :
If you want to save SkiaSharp bitmaps to files , have a look at this :https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/graphics/skiasharp/bitmaps/saving#exploring-the-image-formats
Note: BitmapExtensions.cs file is from sample project .By the way , when adding image to project , you need to set Build ACtion of image be Embedded resource .As follow :
Related
I am fairly new to Xamarin and XAML, so forgive me if my question is dumb.
I have an image that sits inside of an absolute layout content, the image is larger than the screen width and height (pinch and pan works). I am now trying to create a grid that sits on top of the image and eventually populate each cell with a button (a crude way of getting X,Y position). It is crude, I'll admit it, but I would like to do it, if anything, I'll learn what not to do.
This is my XAML,
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MyProject.Code"
x:Class="MyProject.Views.myImage"
HeightRequest="771"
WidthRequest="900">
<ContentPage.Content>
<AbsoluteLayout HorizontalOptions="FillAndExpand">
<local:PinchAndPanContainer>
<Image Source="map.png"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand"
Aspect="Fill"
Opacity="50"/>
</local:PinchAndPanContainer>
</AbsoluteLayout>
</ContentPage.Content>
</ContentPage>
And this is my .cs
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace MyProject.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class myImage: ContentPage
{
public myImage()
{
InitializeComponent();
// Creates the grid
InitializeGrid(2);
}
void InitializeGrid(int res)
{
Grid grid = new Grid();
var red = new BoxView { Color = Color.Red };
var grn = new BoxView { Color = Color.Green };
var blu = new BoxView { Color = Color.Blue };
var yel = new BoxView { Color = Color.Yellow };
grid.WidthRequest = 900;
grid.HeightRequest = 771;
grid.VerticalOptions = LayoutOptions.FillAndExpand;
grid.HorizontalOptions = LayoutOptions.FillAndExpand;
for (int MyCount = 0; MyCount < res; MyCount++)
{
grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
}
grid.Children.Add(red, 0, 0);
grid.Children.Add(grn, 0, 1);
grid.Children.Add(blu, 1, 0);
grid.Children.Add(yel, 1, 1);
}
}
}
How can I achieve a 2x2 grid that will sit on top of the image? I would like to take the C# route in creating the grid so I can create a loop and pass in the "resolution" of the grid, 3x3, 100x100, etc.
When I execute this, nothing happens. Even if I comment out almost the entire XAML that displays the image, I still get nothing. Not sure where to go from here.
Add a name to your AbsoluteLayout (i.e. x:Name="layout") so you can parent your grid to it via .Children.Add
I made a few 😎 more changes to your InitializeGrid method to setup the grid within the AbsoluteLayout properly
FYI: Creating grids with a large number of elements will be a huge performance issue.
Example:
void InitializeGrid(int res)
{
var grid = new Grid
{
RowSpacing = 0,
ColumnSpacing = 0
};
AbsoluteLayout.SetLayoutBounds(grid, new Rectangle(1, 1, 1, 1));
AbsoluteLayout.SetLayoutFlags(grid, AbsoluteLayoutFlags.All);
for (int MyCount = 0; MyCount < res; MyCount++)
{
grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
}
grid.Children.Add(new BoxView { Color = Color.Red, Opacity=0.5 }, 0, 0);
grid.Children.Add(new BoxView { Color = Color.Green, Opacity = 0.5 }, 0, 1);
grid.Children.Add(new BoxView { Color = Color.Blue, Opacity = 0.5 }, 1, 0);
grid.Children.Add(new BoxView { Color = Color.Yellow, Opacity = 0.5 }, 1, 1);
layout.Children.Add(grid);
}
Output:
This piece of code for showing a QR code in a Xamarin.Forms app works in iOS but not on Android:
let barCode = ZXingBarcodeImageView(HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand,
BarcodeFormat = ZXing.BarcodeFormat.QR_CODE,
BarcodeValue = foo)
barCode.BarcodeOptions.Width <- 500
barCode.BarcodeOptions.Height <- 500
mainLayout.Children.Add(barCode)
There's no error in the log, no exception thrown. Tried many heights and widths and different LayoutOptions to no avail. How can I debug this?
Luckily, I just had to play around with ZXing.Net.Mobile in my own Xamarin.Forms project. Where I managed to display the QRCode for both iOS and Android with the next C# code:
ZXingBarcodeImageView GenerateQR(string codeValue)
{
var qrCode = new ZXingBarcodeImageView
{
BarcodeFormat = BarcodeFormat.QR_CODE,
BarcodeOptions = new QrCodeEncodingOptions
{
Height = 350,
Width = 350
},
BarcodeValue = codeValue,
VerticalOptions = LayoutOptions.CenterAndExpand,
HorizontalOptions = LayoutOptions.CenterAndExpand
};
// Workaround for iOS
qrCode.WidthRequest = 350;
qrCode.HeightRequest = 350;
return qrCode;
}
Please note that there is a know issue in this library, and you have to set explicitly the WidthRequest & HeightRequest.
P.S.: More or less the same issue have been discussed here as well.
I have a StackLayout holding some elements for a custom cell in a ListView. The problem I am running in to is that my images are not landing on full pixel boundaries. This is causing the straight lines in my graphics to become blurry as they are not landing on pixel boundaries. Is there a way for me to easily prevent this behavior, perhaps in a custom renderer?
public InputEditCell()
{
image = new Image { HorizontalOptions = LayoutOptions.Start };
image.SetBinding(Image.SourceProperty, new Binding("Image.ImageNameSelect"));
image.BindingContext = _tempInputViewModel;
var tappedImageGesture = new TapGestureRecognizer
{
Command = new Command(OnImageTapped),
CommandParameter = image
};
image.GestureRecognizers.Add(tappedImageGesture);
nameEntry = new Entry()
{
TextColor = Color.FromHex("E60006"),
FontSize = Device.GetNamedSize(NamedSize.Medium, typeof(Entry)),
VerticalOptions = LayoutOptions.Center,
HorizontalOptions = LayoutOptions.FillAndExpand
};
nameEntry.SetBinding(Entry.TextProperty, "Name");
nameEntry.BindingContext = _tempInputViewModel;
var acceptImage = new Image
{
Source = ResourceHandler.GetAcceptImage(),
VerticalOptions = LayoutOptions.Center,
HorizontalOptions = LayoutOptions.End,
};
var tappedAcceptGesture = new TapGestureRecognizer
{
Command = new Command(OnAcceptTapped),
CommandParameter = acceptImage
};
acceptImage.GestureRecognizers.Add(tappedAcceptGesture);
var cancelImage = new Image
{
Source = ResourceHandler.GetCancelImage(),
VerticalOptions = LayoutOptions.Center,
HorizontalOptions = LayoutOptions.End,
};
var tappedCancelGesture = new TapGestureRecognizer
{
Command = new Command(OnCancelTapped),
CommandParameter = cancelImage
};
cancelImage.GestureRecognizers.Add(tappedCancelGesture);
var viewLayout = new StackLayout {
Orientation = StackOrientation.Horizontal,
Children = { image, nameEntry, acceptImage, cancelImage },
Padding = new Thickness(10, 10, 10 ,10)
};
View = viewLayout;
View.GestureRecognizers.Clear();
View.GestureRecognizers.Add(new TapGestureRecognizer());
}
How to Resize the image in windows phone 8.0 application using C# without loss of quality and to display full image
What I did,
My XAML Code:
<StackPanel Orientation="Vertical">
<TextBlock Text="Select Image" FontSize="45" Height="106"></TextBlock>
<Image Name="ImgPrev" Height="455" Stretch="None" ></Image>
</StackPanel>
My C# code
public MainPage()
{
InitializeComponent();
// Sample code to localize the ApplicationBar
//BuildLocalizedApplicationBar();
BitmapImage image = new BitmapImage();
image.SetSource(Application.GetResourceStream(new Uri(#"Assets/Bug.jpg", UriKind.Relative)).Stream);
image.DecodePixelType = DecodePixelType.Logical;
image.CreateOptions = BitmapCreateOptions.BackgroundCreation;
image.CreateOptions = BitmapCreateOptions.DelayCreation;
Image img = new Image();
img.Source = image;
WriteableBitmap wb = new WriteableBitmap(image);
wb.Resize(1000, 1000, WriteableBitmapExtensions.Interpolation.Bilinear);
using(MemoryStream stream=new MemoryStream())
{
wb.SaveJpeg(stream, 1000, 1000, 0, 100);
BitmapImage resize = new BitmapImage();
resize.SetSource(stream);
ImgPrev.Source = resize;
}
}
The original image
Actual size of the image is 38 MB, Dimention 10240x6400 , height:10240, width:6400
What result I am getting is below image
I'm trying to dynamically build a live tile.
It runs fine thanks to some SO suggestions and I have this code:
WriteableBitmap wbmp = new WriteableBitmap(173, 173);
TextBlock text = new TextBlock() { FontSize = (double)Resources["PhoneFontSizeLarge"], Foreground = new SolidColorBrush(Colors.White) };
text.Text = "my text";
wbmp.Render(text, new TranslateTransform() { Y = 20 });
wbmp.Invalidate();
// save image to isolated storage
using (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream imageStream = new IsolatedStorageFileStream("/Shared/ShellContent/MyImage.jpg", System.IO.FileMode.Create, isf))
{
wbmp.SaveJpeg(imageStream, wbmp.PixelWidth, wbmp.PixelHeight, 0, 100);
}
}
The problem is that the tile has a black (or, better, transparent) background. I would like to use accent background color, how can I do it?
Solved in this way:
Canvas can = new Canvas();
can.Background = (SolidColorBrush)Application.Current.Resources["PhoneAccentBrush"];
can.Width = 173;
can.Height = 173;
wbmp.Render(can, null);
You're better to use Resources["TransparentBrush"] as the background, and then save to png, otherwise, your tile will be the wrong color on a theme change.