Create dynamic profile image in UWP app - drawing

I want to display profile images for users in my app. If no image is available from data source I want to generate those dynamic images Microsoft uses (containing the initials of a persons name).
Is this possible in UWP? I have found samples resulting in types from Windows.Graphics.Imaging namespace but they are manipulating existing images and not creating new ones.

RenderTargetBitmap has option to render your UI Elements to Images which can almost match the Image Format that you are looking for with little fiddling. Below is the method that will render the Image from a Grid.
public static async Task<IRandomAccessStream> RenderToRandomAccessStream(this UIElement element)
{
RenderTargetBitmap rtb = new RenderTargetBitmap();
await rtb.RenderAsync(element);
var pixelBuffer = await rtb.GetPixelsAsync();
var pixels = pixelBuffer.ToArray();
// Useful for rendering in the correct DPI
var displayInformation = DisplayInformation.GetForCurrentView();
var stream = new InMemoryRandomAccessStream();
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, stream);
encoder.SetPixelData(BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Premultiplied,
(uint)rtb.PixelWidth,
(uint)rtb.PixelHeight,
displayInformation.RawDpiX,
displayInformation.RawDpiY,
pixels);
await encoder.FlushAsync();
stream.Seek(0);
return stream;
}
Taken from Render XAML to image, Blur app UI, or how to enable awesome user experiences in your UWP app
But there is a catch here. RenderTargetBitmap.RenderAsync(UIElement Reference) will only render an element that is attached to VisualTree. i.e, it can only convert a UIElement to Grid if it is present on the View. (Trust Me, Setting Visibility to Collapsed will not work).
So what I ended up doing is setting the Grid Width/Height to 50 But Image Width/Height to 60.
See My XAML
<Grid x:Name="LayoutRoot" VerticalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid Width="50" Height="50" Visibility="Visible" Name="GRDData" Background="LightBlue">
<TextBlock Name="tbModded" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
<Image Width="60" Height="60" x:Name="bgImage" Margin="10,0"/>
<TextBlock Grid.Column="1" Margin="10,0">
<Run x:Name="FN" />
<Run x:Name="LN" />
</TextBlock>
</Grid>
Now this is my code behind. Just for the sake of showing that Element is in the backend, I am setting the Grid Background to Red rather than Blue like the way it is in xaml.
private async void MainPage_Loaded(object sender, RoutedEventArgs e)
{
string FirstName = "Test data";
FN.Text = FirstName;
string LastName = "Data Item";
LN.Text = LastName;
string ModdedString = FirstName.Substring(0, 1) + LastName.Substring(0, 1);
tbModded.Text = ModdedString;
GRDData.Background = new SolidColorBrush(Colors.Red);
IRandomAccessStream stream = await RenderToRandomAccessStream(GRDData);
BitmapImage image = new BitmapImage();
image.SetSource(stream);
bgImage.Source = image;
}
End Output Will be

Related

C++ /WinRT - TextBlock, how to dynamically attach and set its position (x, y) to XAML form?

Below was Blank App (C++/WinRT) project.
I am trying to create a TextBlock and set its Text (x,y) property "Left" and "Top" dynamically from MainPage.cpp and display it on runtime XAML form.
However, for testing, code below able to compile successfully and at the runtime result, no TextBlock component "Hellow World!" is shown.
Is there anything wrong or missing ?
namespace winrt::...::implementation
{
MainPage::MainPage()
{
InitializeComponent();
Process();
}
void MainPage::Process()
{
winrt::hstring hs = L"Hello World!";
TextBlock tbx;
tbx.FontFamily( Windows::UI::Xaml::Media::FontFamily(
L"Segoe UI Semibold" ) );
tbx.FontSize(72.0);
tbx.Foreground( SolidColorBrush( Colors::Orange() ) );
tbx.VerticalAlignment( VerticalAlignment::Center );
tbx.TextAlignment( TextAlignment::Center );
tbx.Text( hs );
Window window = Window::Current();
window.Content( tbx );
window.Activate();
}
}
Please advise.
The underlying problem is a XAML layout issue. Here's a little demo that should put you on the right track. I modified your MainPage above to look like this:
MainPage::MainPage()
{
InitializeComponent();
winrt::hstring hs = L"Hello World!";
TextBlock tbx;
tbx.FontFamily(Windows::UI::Xaml::Media::FontFamily(
L"Segoe UI Semibold"));
tbx.FontSize(72.0);
tbx.Foreground(SolidColorBrush(Colors::Orange()));
tbx.VerticalAlignment(VerticalAlignment::Center);
tbx.TextAlignment(TextAlignment::Center);
tbx.Text(hs);
this->Content().as<Panel>().Children().Append(tbx);
}
The XAML page looks like this:
<Page ... >
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<Button x:Name="myButton" >Click Me</Button>
</StackPanel>
</Page>
The basic idea is that you want to add the control to a panel that is managing layout on the main page, rather than adding it to the top level Window object. It may be instructive to play around in the designer a bit to get the desired look, then restructure it into equivalent code using C++ /WinRT.
Ben
Just discovered this works:
TranslateTransform pos;
pos.X( 500 );
pos.Y( 500 );
tbx.RenderTransform( pos )
Alternatively, found a latest video from Microsoft Build 2019, it shown a sample of UWP C++ with XAML with related info within.
Here is the link:
Meet C++/WinRT 2.0: Faster and smarter in the open - BRK4009
[https://www.youtube.com/watch?v=X41j_gzSwOY][1]

HOW TO: Get the Item Selected in NavigationView in C++

I'm new to UWP and I have what I think is a simple problem to solve, but the examples I've found haven't worked. I'm using a navigation view in UWP project and I want to be able to switch page and display in a frame. When I select an item in the navigation view the ItemInvoked event is fired. I know the code to load the page into the frame which I've included below.
void enVigilServer::MainPage::nvSample_ItemInvoked(Windows::UI::Xaml::Controls::NavigationView^ sender, Windows::UI::Xaml::Controls::NavigationViewItemInvokedEventArgs^ args)
{
this->contentFrame->Navigate(Windows::UI::Xaml::Interop::TypeName(SysConf::typeid));
}
My problem is how to determine which item I've selected from the NavigationView to show the relevant page.
Thanks
It's actually related to c++-cx and I will purpose this tag to your issue.
To make the navigation simple we can use the tag system in our app. See the following code:
<NavigationView x:Name="NavigationViewControl" ItemInvoked="NavigationViewControl_ItemInvoked" >
<NavigationView.MenuItems>
<NavigationViewItem Content="A" x:Name="A" Tag="tga" />
<NavigationViewItem Content="B" x:Name="B" Tag="tgb"/>
<NavigationViewItem Content="C" x:Name="C" />
</NavigationView.MenuItems>
<Frame x:Name="contentFrame"/>
</NavigationView>
This is an example, we will add tags to our items. Then we will do the following in our invoke code:
void NavigationVWCX::MainPage::NavigationViewControl_ItemInvoked(Windows::UI::Xaml::Controls::NavigationView^ sender, Windows::UI::Xaml::Controls::NavigationViewItemInvokedEventArgs^ args)
{
auto navitemtag = args->InvokedItemContainer->Tag->ToString();
if (navitemtag == "tga")
{
contentFrame->Navigate(Windows::UI::Xaml::Interop::TypeName(PageA::typeid));
}
if (navitemtag == "tgb")
{
contentFrame->Navigate(Windows::UI::Xaml::Interop::TypeName(PageB::typeid));
}
}
BTW, don't forget to also add tag to your pages, like:
PageB::PageB()
{
InitializeComponent();
this->Tag = "tgb";
}

Sitecore How to get the value inside the field 'Media' of a Media Item

Update 2:
I am still fighting to get the Icon save on the server.
Here what I am doing:
Item item = Sitecore.Context.Database.GetItem(imageId);
var imageIconUrl = Sitecore.Resources.Images.GetThemedImageSource(item.Appearance.Icon, ImageDimension.id32x32);
if (!string.IsNullOrEmpty(imageIconUrl))
{
// download the icon from the url
var iconFullPath = "e:\\pngIcons\\excelIcon.png";
var webClient = new System.Net.WebClient();
var downloadPath = "http://serverName/" + imageIconUrl;
webClient.DownloadFile(downloadPath, iconFullPath);
}
The variable downloadPath contains following string:
http://serverName/sitecore/shell/themes/standard/~/media/E503BA48C89B422D8400393F1C7086A7.ashx?h=32&thn=1&w=32&db=master
At the end what I can see is a png file but there is nothing in it. I also copy the string I get in variable downloadPath and pasted it in browser and I can see the Icon as follow:
Please let me know what I am doing wrong. Or How I can save the Icon. Thanks!!
Original Question:
The sitecore media item has a field "Media". I am talking about this:
I want to access this field. And the reason is:
If I access it with e.g. item.GetMediaStream() then I will get the complete file. I just want to save this little icon some how on the server. Is it possible ?
To get the icon/thumbnail you can use
var icon = Sitecore.Resources.Media.MediaManager.GetThumbnailUrl(mediaItem);
To get the url of the thumbnail.
If you want the stream of the thumbnail you need to use the MediaData object. Like this:
var mediaItem = new MediaItem(item)
var mediaData = new MediaData(mediaItem);
var iconStream = mediaData.GetThumbnailStream();
if (iconStream.Length < 0)
{
// The stream is empty, its probably a file that Sitecore can't
// generate a thumbnail for. Just use the Icon
var icon = item.Appearance.Icon;
}
This will get the icon or thumbnail of the actual media blob that is attached to the media item. If you just want the icon of the Sitecore item, then use Martins method.
If the stream is empty, then Sitecore can't generate a thumbnail for it, so you can just use the icon file for the media item template. item.Appearance.Icon
Appearance section (of Standard Template) has a field called Icon - this is where you can modify icon for the item. There is also a field called Thumbnail - your excel icon is sitting there
You can access the field programmatically, just mind that it starts with two underscores: __Icon:
var iconField = item.Fields["__Icon"];
var thumbnailField = item.Fields["__Thumbnail"];
Update: As you asked, below is the code that saves either of fields into the file on a drive. I have tested the code and confirm successfully stores icon from thumbnail field into the file:
string mediaItemPath = "/sitecore/media library/Files/ExcelFile";
string mediaFiedlName = "Thumbnail"; // also can be "__Icon"
var item = Sitecore.Context.Database.GetItem(mediaItemPath);
var iconField = item.Fields[mediaFiedlName];
if (iconField.HasBlobStream)
{
var thumb = (ImageField)iconField;
var bl = ((MediaItem)thumb.MediaItem).InnerItem.Fields["blob"];
Stream stream = bl.GetBlobStream();
byte[] buffer = new byte[8192];
using (FileStream fs = File.Create("D:\\you_file_name.ico")) // change your path
{
int length;
do
{
length = stream.Read(buffer, 0, buffer.Length);
fs.Write(buffer, 0, length);
}
while (length > 0);
fs.Flush();
fs.Close();
}
}
Update 2: If that does not help then I would advise to look around the way how that icon gets generated on Media field in Sitecore. In the worst case you may do the following - right click that icon and see its url. You will have something similar to what I assign to variable below:
string url = "http://test81/sitecore/shell/Applications/-/media/B4F61650CBE84EE396649602C0C48E1B.ashx?bc=White&db=master&h=128&la=en&mw=640&thn=1&vs=1&ts=b8046903-ae57-4f9d-9dd5-b626ee5eee90";
Of course your URL should have your hostname and media prefix and the rest of parameters. Then use Webclient with that modified URL:
WebClient webClient = new WebClient();
webClient.DownloadFile(url, "e:\\you_file_name.ico");
Not ideal, but may work. Note, that the code above should work in a context of already logged user, so you need to authorise you Webclient prior that (many articles on S.O. how to do that).
Please reply if that approach has worked for you (I've spent decent time writing and testing that code in debugger, so would want to know whether that helped)

How to make a looping/circular ScrollViewer in Windows 8 Metro (C++/XAML)

In a Windows 8 Metro app, is it possible to create a ScrollViewer which upon reaching the last item in the view, it loops back to the first item in the view? If so, how can I achieve this effect?
It is definitely possible. I am solving the problem at the moment and will post work when done. So far it goes something like below.
THe idea is that you hook into the viewchanged event for the scroll viewer, which fires anytime you move the bar. Once there, calculate where you are in the offset and the size of your items, and then you can use that to measure against the actual size of your listbox container or what have you.
Once you know where you are in the offset and know the actual height of your listbox and the height of your items, you know which items are currently visible and which are not. Make sure your list bound to the object is an observable collection implementing the INotifyChanged interface with two way binding. Then you can define a set of objects to rotate back and forth based on where in the scrolling you are.
Another option is to try a different starting point, perhaps a single control with a marquee and a scrollbar under it?
XAML
</UserControl.Resources>
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ScrollViewer x:Name="ScrollViewer1">
<ListBox x:Name="SampleListBox" Background="White" ItemsSource="{Binding Path=sampleItems}" ItemTemplate="{StaticResource sampleTemplate}" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Grid.Row="0" Grid.RowSpan="2">
</ListBox>
</ScrollViewer>
</Grid>
Code Behind
public sealed partial class MainPage : Page
{
List<SampleItem> sampleItems;
const int numItems = 15;
public MainPage()
{
sampleItems = new List<SampleItem>();
for (int i = 0; i < numItems; i++)
{
sampleItems.Add(new SampleItem(i));
}
this.InitializeComponent();
SampleListBox.ItemsSource = sampleItems;
ScrollViewer1.ViewChanged += ScrollViewer1_ViewChanged;
}
void ScrollViewer1_ViewChanged(object sender, ScrollViewerViewChangedEventArgs e)
{
ScrollViewer viewer = sender as ScrollViewer;
ListBox box = viewer.Content as ListBox;
ListBoxItem lbi = box.ItemContainerGenerator.ContainerFromIndex(0) as ListBoxItem;
double elementSize;
if (lbi == null)
return;
elementSize = lbi.ActualHeight;
} /// <summary>
/// Invoked when this page is about to be displayed in a Frame.
/// </summary>
/// <param name="e">Event data that describes how this page was reached. The Parameter
/// property is typically used to configure the page.</param>
protected override void OnNavigatedTo(NavigationEventArgs e)
{
}
}
public class SampleItem
{
public String ItemCount { get; set; }
public SampleItem(int itemCount)
{
ItemCount = itemCount.ToString();
}
}
I don't believe there is a control like that in WinRT/XAML, so you would need to implement a custom control. There are many approaches you could take, but I would probably avoid using the ScrollViewer and handle manipulation events directly since it might not be easy to bend ScrollViewer's behavior to your requirements. I would control the scroll offset based on the manipulation events and based on the scroll offset - position the elements in the view - e.g. using a Canvas control. You would need to reposition elements in the items panel depending on a scroll offset, so that for example items that go beyond the view port on one end are moved to the other end. It would involve custom dependency properties, item containers etc. Probably at least a few hours of work if you know all these APIs.

Facebook iOS-sdk and posting a local (UI)Image

I have successfully used photos.upload api to upload local images to the users album.
How to upload local images with formatted links? The photos.upload does support adding the caption text, but I can't embed html-links to the caption. Is there a way to do this using perhaps the Graph-api?
I'm not sure about the caption itself, but here is a way to post the image along with a message to the user's wall. The message text can have imbedded links in it with no problem.
Facebook* fb = [(AppDelegate *) [[UIApplication sharedApplication] delegate] facebook];
NSData* imageData = UIImageJPEGRepresentation([UIImage imageNamed: #"A.jpg"], 90);
NSMutableDictionary * params = [NSMutableDictionary dictionaryWithObjectsAndKeys: [fb accessToken],
#"access_token",
#"some message here...with a link http://www.google.com",
#"message",
imageData,
#"source",
nil];
[fb requestWithGraphPath: #"me/photos"
andParams: params
andHttpMethod: #"POST"
andDelegate: self];