I'm trying to set a remote image for a flipTileData:
var tileData = new FlipTileData();
tileData.BackgroundImage = new Uri("http://slurm.trakt.us/images/fanart/735.8-940.jpg", UriKind.RelativeOrAbsolute);
tileData.Count = count;
tileData.BackTitle = title;
tileData.Title = title;
tileData.WideBackgroundImage = new Uri("http://slurm.trakt.us/images/fanart/735.8-940.jpg", UriKind.RelativeOrAbsolute);
ShellTile.Create(new Uri(string.Format("/ShowPage.xaml?id={0}", id), UriKind.Relative), tileData, true);
However, like the example above the image doesn't show but other images work perfectly just like the one below:
"http://slurm.trakt.us/images/fanart/97.14-940.jpg"
Is there any limitation or constraint that I have to be aware of for WP8 tile images? I really can't understand why some work and others don't.
Based on MS Doc, there are some restrictions about the size of the image as well as the time to be downloaded then you're using external Uris (resources)
If references a remote resource, the maximum
allowed size of the Tile image is 80 KB, with a maximum download time
of 15 seconds.
from http://msdn.microsoft.com/en-us/library/ff402545(VS.92).aspx.
So, I know that the problem you're facing it with the WideBackgroundImage , and the working has a size of 130KB, and the non-working image has a size of 161KB. So, I think you should be using images with that size of 130KB or lower for the WideBackgroundImage property, and that may work in your case. I haven't found a documented constraint on this property, but it makes sense if Microsoft is also applying this restriction.
Herber
Related
I need to show the preview thumbnails of high resolution images in a control for user selection. I currently use ImageListView to load images.
This works fine for low to medium resolution images.But when it comes to showing thumbnails of very high resolution images there is a noticeable delay.Sample image can be downloaded from https://drive.google.com/open?id=1Qgu_aVXBiMlbHluJFU4fBvmFC45-E81C
The image size is around 5000x3000 pixels and size is around 12 MB.The issue can be replicated by using 1000 copies of this image.
The issue screen capture is uploaded here
https://giphy.com/gifs/ZEH3T3JTfN42OL3J1A
The images are loaded using a background worker
foreach (var f in filepaths)
{
imageListView1.Items.Add(f);
}
1. In order to solve this issue I tried resizing large resolution images and adding the resized image to ImageListView ... but for resizing there is a heavy time consumption and thumbnail generation is slow.
Bitmap x = UpdatedResizeImage2(new Bitmap(f), new Size(1000, 1000));
string q = Path.GetTempPath() + Path.GetFileName(f);
x.Save(Path.GetTempPath() + Path.GetFileName(f));
x.Dispose();
imageListView1.Items.Add(Path.GetTempPath() + Path.GetFileName(f));
2. I have also tried Image.CreateThumbnail Method but this is also quite slow.
Is there a better way to solve this issue?
I would suggest using image processing library such ImageMagick.
ImageMagick has optimized this feature and you have Magick.NET a nuget package for .NET.
It is simple and straight forward:
var file = new FileInfo(#"c:\temp\input.jpg");
using (MagickImage image = new MagickImage(file))
{
{
image.Thumbnail(new MagickGeometry(100, 100));
image.Write(#"C:\temp\thumbnail.jpg");
}
}
example I made:
Here is some documentation and references that might be useful:
https://imagemagick.org/Usage/thumbnails/#creation
http://www.imagemagick.org/Usage/thumbnails/
https://github.com/dlemstra/Magick.NET
https://www.smashingmagazine.com/2015/06/efficient-image-resizing-with-imagemagick/
https://devblogs.microsoft.com/dotnet/net-core-image-processing/
https://weblogs.asp.net/bleroy/resizing-images-from-the-server-using-wpf-wic-instead-of-gdi
Alternatives to System.Drawing for use with ASP.NET?
You could use WPF interop and use the DecodePixelWidth/Height properties. They use underlying Windows imaging layer technology ("Windows Imaging Component") to create an optimized thumbnail, saving lots of memory (and possibly CPU): How to: Use a BitmapImage (XAML)
You can also use WPF/WIC by code, with a code like this (adapted from this article The fastest way to resize images from ASP.NET. And it’s (more) supported-ish.. You just need to add a reference to PresentationCore and WindowsBase which shouldn't be an issue for a desktop app.
// needs System.Windows.Media & System.Windows.Media.Imaging (PresentationCore & WindowsBase)
public static void SaveThumbnail(string absoluteFilePath, int thumbnailSize)
{
if (absoluteFilePath == null)
throw new ArgumentNullException(absoluteFilePath);
var bitmap = BitmapDecoder.Create(new Uri(absoluteFilePath), BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.None).Frames[0];
int width;
int height;
if (bitmap.Width > bitmap.Height)
{
width = thumbnailSize;
height = (int)(bitmap.Height * thumbnailSize / bitmap.Width);
}
else
{
width = (int)(bitmap.Width * thumbnailSize / bitmap.Height);
height = thumbnailSize;
}
var resized = BitmapFrame.Create(new TransformedBitmap(bitmap, new ScaleTransform(width / bitmap.Width * 96 / bitmap.DpiX, height / bitmap.Height * 96 / bitmap.DpiY, 0, 0)));
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(resized);
var thumbnailFilePath = Path.ChangeExtension(absoluteFilePath, thumbnailSize + Path.GetExtension(absoluteFilePath));
using (var stream = File.OpenWrite(thumbnailFilePath))
{
encoder.Save(stream);
}
}
Otherwise there are lots of tools out there like MagicScaler, FreeImage ImageSharp, ImageMagick, Imazen, etc. Most were written for ASP.NET/Web server scenarios (for which WPF is officially not supported but works, read the article) and are also cross-platform which you don't seem to need. I'm not sure they're generally faster or use less memory than builtin Windows technology, but you should test all this in your context.
PS: otherwise there's no magic bullet, bigger images take more time.
There's also NetVips, the C# binding for libvips.
It's quite a bit quicker than Magick.NET: between 3x and 10x faster, depending on the benchmark.
Thumbnailing is straightforward:
using NetVips;
var image = Image.Thumbnail("some-image.jpg", 128);
image.WriteToFile("x.jpg");
There's an introduction in the documentation.
Most of answers approach is to resize bitmap and then save it. Its a bit offcourse slow, specially if you say very high resolution.
Why not use existing thumbnail created by windows explorer ? This is fastest way of all (specially if you use smaller thumbnails).
//https://stackoverflow.com/a/1751610
using Microsoft.WindowsAPICodePack.Shell;
var shellFile = ShellFile.FromFilePath(pathToYourFile); Bitmap
Image image = shellFile.Thumbnail.LargeBitmap;
Nuget : https://www.nuget.org/packages/WindowsAPICodePack-Shell (around 600KB)
Note: Its same as others, if thumbnail arent cached already.
I have a Windows Store app written in C# that works with photos. I want to show the last photo the user selected in the app in the medium size live tile (150 x 150). I am using the code below to do it. When I run the app I don't get any errors, but I don't see the selected photo in the live tile either. I know that I am doing at least some things right. I say this because if the user hasn't selected a photo yet, then I show a test image and I do see that image in the tile. But the test image comes from the app package using the ms-appx protocol, not from the app storage area.
I found a few SO posts on the subject but they are all for Windows Phone. I looked at the KnownFolders list for Windows Store app files, but nothing seemed to map to the SharedContent folder required for files meant for live tile use in Windows Phone. What is wrong with my code?
Note, the vvm.ActiveVideomark.GetThumbnail() call simply retrieves a bitmap as a WriteableBitmap object. As you can see in the code, I am resizing the image to the size required by the Medium live tile (150 x 150). ToJpegFileAsync() is an extension method that encodes a WriteableBitmap object to jpeg bytes and then writes those bytes to a file using the given file name. Both of these calls are well-tested and are not the source of the problem as far as I know.
TileUpdateManager.CreateTileUpdaterForApplication().Clear();
TileUpdateManager.CreateTileUpdaterForApplication().EnableNotificationQueue(true);
var tileXml = TileUpdateManager.GetTemplateContent(TileTemplateType.TileSquare150x150Image);
var tileImage = tileXml.GetElementsByTagName("image")[0] as XmlElement;
// Got a current photo?
if (vvm.ActiveVideomark == null)
// No, just show the regular logo image.
tileImage.SetAttribute("src", "ms-appx:///Assets/Logo.scale-100.png");
else
{
// Resize it to the correct size.
WriteableBitmap wbm = await vvm.ActiveVideomark.GetThumbnail();
WriteableBitmap wbm2 = wbm.Resize(150, 150, WriteableBitmapExtensions.Interpolation.Bilinear);
// Write it to a file so we can pass it to the Live Tile.
string jpegFilename = "LiveTile1.jpg";
StorageFile jpegFile = await wbm2.ToJpegFileAsync(jpegFilename);
// Yes, show the selected image.
tileImage.SetAttribute("src", jpegFile.Path);
}
The src attribute must contain a URI with ms-appx:///, ms-appdata:///local, or http[s]:// schemes. The StorageFile.Path property, as you're using with jpegFile.Path, is a local filesystem pathmame like c:\users\Robert\AppData... which won't be valid. So create your tile images in local app data, and then use ms-appdata:///local/ to refer to them in tile payloads.
Greetings all,
Thanks for reading and sharing any insights. I've created a new simple Windows Phone 7 application. I have two Image objects on the form I would like to update with various .png files. I have included the .png files into my project, and I believe I am building proper URi resources pointing to these files.
Uri myImage1URi = new Uri( strImage1, UriKind.RelativeOrAbsolute );
Uri myImage2URi = new Uri( strImage2, UriKind.RelativeOrAbsolute );
System.Windows.Media.Imaging.BitmapImage bi1 = new System.Windows.Media.Imaging.BitmapImage(myImage1URi);
System.Windows.Media.Imaging.BitmapImage bi2 = new System.Windows.Media.Imaging.BitmapImage(myImage2URi);
image1.Source = bi1;
image1.Stretch = Stretch.Fill;
image2.Source = bi2;
image2.Stretch = Stretch.Fill;
This alone is not accomplishing what I want (to update the images to the two from the URi's).
I know there is something a bit off going on (IE: I am doing something dumb) in that all of the BitmapImage class descriptions mention that I have to do a .BeginInit() before I work with the BitmapImage object, and a .EndInit() call afterwards. These method calls don't work for me, so I know something is amiss....
Or maybe I am competely off base and I simply need a way to tell my main window to repaint itself? That thought has occurred to me as well.
Thanks again.
The following will load an image that is in the appropriate path and is set as having a build action content.
myImg.Source = new BitmapImage(new Uri("/images/filename.png", UriKind.Relative));
It assumes XAML on the page like:
<Image x:Name="myImg" />
This seems very similar to what you're doing. Simplify what you're doing ot get it working.
Does it work with just using one image?
Is the path in strImageN a valid path?
Do the image files have their build action set to Content?
I believe with JPGs, the width and height information is stored within the first few bytes. What's the easiest way to get this information given an absolute URI?
First, you can request the first hundred bytes of an image using the Range header.
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Headers.Set(HttpRequestHeader.UserAgent, "Range: bytes=0-100");
Next, you need to decode. The unix file command has a table of common formats, and the locations of key information. I'd suggest installing Cygwin and taking a look at /usr/share/file/magic.
For gif's and png's, you can easily get the image dimensions from the first 32 bytes. However, for JPEGs, #Andrew is correct in that you can't reliably get this information. You can figure out if it has a thumbnail, and the size of the thumbnail.
The get the actual jpeg size, you need to scan for the start of frame tag. Unfortunately, one can't reliably determine where this is going to be in advance, and a thumbnail could push it several thousand bytes into the file.
I'd recommend using the range request to get the first 32 bytes. This will let you determine the file type. After which, if it's a JPEG, then download the whole file, and use a library to get the size information.
I am a bit rusty at this, but with jpeg, it might not be as simple as it seems. Jpeg has a header within each segment of data which has its own height / width and resolution. jpeg was not designed to be streamed easily. You might need to read the entire image to find the width and height of each segment within the jpeg to get the entire width and height.
If you absolutely need to stream an image consider changing to another format which is easier to stream, jpeg is going to be tough.
You could do it if you can develop a server side program that would seek forward and read the header of each segment to compute the width and height of the segment.
It's a bit Heath Robinson, but since browsers seem to be able to do it perhaps you could automate IE to download the image within a webpage and then interrogate the browser's DOM to reveal the dimensions before the image has finished downloading?
Use this code:
public static async Task<Size> GetUrlImageSizeAsync(string url)
{
try
{
var request = WebRequest.Create(url);
request.Headers.Set(HttpRequestHeader.UserAgent, "Range: bytes=0-32");
var size = new Size();
using (var response = await request.GetResponseAsync())
{
var ms = new MemoryStream();
var stream = response.GetResponseStream();
stream.CopyTo(ms);
var img = Image.FromStream(ms);
size = img.Size;
}
return size;
}
catch
{
return new Size();
}
}
this is how my code look now:
System.Drawing.Image objImage = System.Drawing.Image.FromFile(Server.MapPath("aaa.jpg"));
int height = objImage.Height;
int width = objImage.Width;
System.Drawing.Bitmap bitmapimage = new System.Drawing.Bitmap(objImage, width, height);
System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bitmapimage);
System.Drawing.Image bitmap2 = (System.Drawing.Image)Bitmap.FromFile(Server.MapPath("sem.png"));
g.DrawImage(bitmap2, (objImage.Width - bitmap2.Width) / 2, (objImage.Height - bitmap2.Height) / 2);
MemoryStream stream = new MemoryStream();
bitmapimage.Save(stream, ImageFormat.Jpeg);
String saveImagePath = Server.MapPath("ImagesMerge/") + "aaa.jpg";
bitmapimage.Save(saveImagePath);
imgBig.ImageUrl = saveImagePath;
The problem I have now is that the image is not displayed in browser, I don't understand why .
like jmaglasang said, I would suggest to you to use an ashx file and if you don't need to keep the image, just send the image stream directly to the http without saving it on the disk
so you only need to do something like
<img src="Handler.ashx?action=merge&image1=blah.jpg&image2=bloh.jpg">
look at this code for an example of how to send an image made in memory that does not exist on the drive
Bitmap is a subclass of Image, so there no need to convert Bitmap to Image. It already is...
Probably because saveImagePath will be a local path (such as c:\somepath\aaa.jpg) that is not reachable from the browser. You probably want to set the ImageUrl = "ImagesMerge/aaa.jpg" instead.
You can also try:
imgBig.ImageUrl = ResolveUrl(saveImagePath);
EDIT:
If saveImagePath is under the WebApplication Directory, doing some modifications on the directory structure i.e. modifying files, deleting and creating can cause the application pool to recycle, and once it reaches the maximum recycle count the application pool will be stopped causing "Server unavailable" error.
I would suggests to add/save/modify images on a separate directory (not under the Apps Directory) then create a Handler(ASHX) that will read the images, just an advice though.
MapPath will give you a physycal address, not a virtual address which is what the browser needs to get to the image.
You might be forgetting to set the Response.Headers. Check out the following example that shows how to create bar chart images and then display it on the screen:
http://www.highoncoding.com/Articles/399_Creating_Bar_Chart_Using__NET_Graphics_API.aspx