I want to load images into a Pivot header to substitute the lack of a Gallery control in WP7. I'm trying to populate them from a URL, and want to make sure that the image is not kept in the cache (by setting UriSource = null) to make sure that they don't take too much resources.
There's no way to do this in the XAML itself, can someone give me sample code to handle this from code-behind. my attempts have been unsuccessful. what am I doing wrong here?
public class PhotoGalleryVM
{
public ObservableCollection<BitmapImage> Images
{
get
{
ObservableCollection<BitmapImage> list = new ObservableCollection<BitmapImage>();
foreach (RoomImage r in App.appData.currentChoices.roomImages)
{
BitmapImage img = new BitmapImage(new Uri(Uri.UnescapeDataString(r.largeUri)));
img.UriSource = null;
list.Add(img);
}
return list;
}
}
}
There is an option that enables to ignore image cache:
bitmapImage.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
Read more at msdn
Related
In the end, my goal is to send a raw image data from the front-end, then split that image into however many pages, and lastly send that pdf back to the front-end for download.
But every time I use the theDoc.addImageFile(), it tells me that the "Image is not in a suitable format". I'm using this as reference: https://www.websupergoo.com/helppdfnet/source/5-abcpdf/doc/1-methods/addimagefile.htm
To troubleshoot, I thought that the image might not be rendering correctly, so I added a File.WriteAllBytes to view the rendered image and it was exactly what I wanted, but still not adding to the PDF. I also tried sending the actual path of a previously rendered image thinking that the new image might not have been fully created yet, but it also gave me the same error. Lastly, I thought PNGs might be problematic and changed to JPG but it did not work.
Here is the code:
[HttpPost]
public IActionResult PrintToPDF(string imageString)
{
// Converts dataUri to bytes
var base64Data = Regex.Match(imageString, #"data:image/(?<type>.+?),(?<data>.+)").Groups["data"].Value;
var binData = Convert.FromBase64String(base64Data);
/* Ultimately will be removed, but used for debugging image */
string path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
string imgName= "Test.jpg";
string filename = Path.Combine(path, imgName);
System.IO.File.WriteAllBytes(filename, binData);
/***********************************************************/
using (Doc theDoc = new Doc())
{
// Using explicit path
theDoc.AddImageFile(#"C:\Users\User\Documents\Test.jpg", 1);
// Using variable
//theDoc.AddImageFile(filename, 1);
// What I really want
//theDoc.AddImageFile(binData , 1);
theDoc.Page = theDoc.AddPage();
theDoc.AddText("Thanks");
Response.Headers.Clear();
Response.Headers.Add("content-disposition", "attachment; filename=test.pdf");
return new FileStreamResult(theDoc.GetStream(), "application/pdf");
}
}
Try something like this (not tested, but cleaned up from my own code):
public int AddImageFile(Doc doc, byte[] data, int insertBeforePageID)
{
int pageid;
using (var img = new XImage())
{
img.SetData(data);
doc.Page = doc.AddPage(insertBeforePageID);
pageid = doc.Page;
doc.AddImage(img);
img.Clear();
}
return pageid;
}
To add a JPEG from a byte array you need Doc.AddImageData instead of Doc.AddImageFile. Note that AddImageFile / AddImageData do not support PNG - for that you would definitely need to use an XImage. The XImage.SetData documentation has the currently supported image formats.
This is quite vexing.
I am working on an app for image management. Part of the value is the ability to store images in sub-folders based on image properties, eg. creation date.
If I store the image source in a shallow folder (app\images\img.jpg), everything works fine.
If I store the image in KnownFolders.Pictures\source\year\month\day\img.jpg, Image does not render. (Yes, that specific path won't work, I am trying to give you a sense of how the path is constructed)...
The file is actually there. The path is correct (I can open it in a browser, e.g.). The app has access to the file.
But it does not render the bitmap.
I tried to render the bitmap manually using
new BitmapImage(new Uri("KnownFolders.Pictures\source\year\month\day\img.jpg"),UriKind.Absolute))
That does not render anything. (Again, assume the path is valid and has a file at its bottom).
What Am I Missing?
The head scratcher: for GIF anims, I am using Thomas Levesque's useful component: https://github.com/XamlAnimatedGif. That one, unfortunately, does only render gifs... and it does so even when the path is the one given above. So the Standard IMAGE control does not render correctly, but Thomas's control does... infuriating.
An UWP app can't load a BitmapImage from an absolute URL to a file in a folder structure below the Pictures Library Folder.
So this won't work:
var relativePath = #"source\year\month\day\img.jpg";
var imageFile = await KnownFolders.PicturesLibrary.GetFileAsync(relativePath);
var bitmapImage = new BitmapImage(new Uri(imageFile.Path));
However, you could do this:
var relativePath= #"source\year\month\day\img.jpg";
var imageFile = await KnownFolders.PicturesLibrary.GetFileAsync(relativePath);
var bitmapImage = new BitmapImage();
using (var stream = await imageFile.OpenAsync(FileAccessMode.Read))
{
await bitmapImage.SetSourceAsync(stream);
}
So, after way too much time spent on this...
First, link to DataContextChanged of the IMAGE element. In there, parse the DataContext out. If you are using the IMAGE outside of an ItemsControl etc, this is not required...
private async void ImageView_DataContextChanged(FrameworkElement sender, DataContextChangedEventArgs args)
{
if (sender is Image)
{
Image img = (Image)sender;
if (img.DataContext is ImageView)
{
MyViewDataContext dc = (MyViewDataContext)img.DataContext;
img.Source = await dc.bitmap();
}
}
}
And here the implementation of MyViewDataContext.bitmap() which has a property called source that yields, you guessed it, absolute paths:
public async Task<BitmapImage> MyViewDataContext.bitmap()
{
if (_bitmap == null)
{
try
{
StorageFile file = await StorageFile.GetFileFromPathAsync(source);
bool r = Windows.Storage.AccessCache.StorageApplicationPermissions.FutureAccessList.CheckAccess(file);
if (r)
{
using (IRandomAccessStream fileStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read))
{
// create a new bitmap, coz the old one must be done for...
_bitmap = new BitmapImage();
// And get that bitmap sucked in from stream.
await _bitmap.SetSourceAsync(fileStream);
}
}
}
catch (Exception e)
{
_bitmap = null;
}
}
return _bitmap;
}
BitmapImage _bitmap;
I cache the resulting bitmap until I dispose of this MyViewDataContext.
I am now most concerned about memory. This one worries me:
How to dispose BitmapImage cache?
So, as a tech debt, I am going to address the potential mem leaks later, once this whole thing is on the test bench and I can take a look at its runtime behavior...
To access the folders and libraries represented by the properties of this class, specify the corresponding capabilities in your app manifest. For example, to access KnownFolders.PicturesLibrary, specify the Pictures Library capability in the app manifest.
Hope this will help
KnowFolders
In Windows Phone 8.1 , i have a ListView. My list is populated with an ObservableColection of Pictures. In class Pictures i have pictureName , and bitmapImage.
In ListView_Item_Click , i want to click a Picture and send it to another xaml page.
BitmapImage img = new BitmapImage();
img = ((Picture)e.ClickedItem).Image;//imi selectez imaginea care doresc!!
var image = new Image();
image.Source = img;
Frame.Navigate(typeof(Page2), image); in mainpage.xaml.cs
I wouldn't pass BitmapImage as a parameter of Frame.Navigate - it's not serializable and there will be a problem with SuspensionManager or Resuming/Suspending events.
The solution depends on your images - where to they come from - if it's a file, then you can just pass a path to that file and then in OnNavigated (for example), set the ImageSource from file.
Other method may be to set BitmapImage in target page, before it's navigated to - for example use static property:
public class TargetPage : Page, INotifyPropertyChanged
{
private static BitmapImage bmpImage;
public static BitmapImage BmpImage
{
get { return bmpImage; }
set { bmpImage = value; RaisePropertyChanged("BmpImage"); }
}
// rest of the code
Then you can just set the image before navigating:
TargetPage.BmpImage = img;
Frame.Navigate(typeof(TargetPage));
Also you should remember about Suspending and Resuming events and the case when your app is being terminated while it's Suspended. In every case you should somehow remember the source of the image - using SuspensionManager, PageState, Settings or other method.
I am getting a list of objects in Windows Phone, and show them in a listbox with databinding.
some image urls are not valid, so after every object is added in the list, i run the following code to check and replace, if not valid
private void CheckLinkUrl(Person p)
{
Uri filePath = new Uri(p.img_url);
string correct = p.img_url;
HttpWebRequest fileRequest = HttpWebRequest.CreateHttp(filePath);
fileRequest.Method = "HEAD";
fileRequest.BeginGetResponse(result =>
{
HttpWebRequest resultInfo = (HttpWebRequest)result.AsyncState;
HttpWebResponse response;
try
{
response = (HttpWebResponse)resultInfo.EndGetResponse(result);
}
catch (Exception e)
{
p.img_url = "http://somethingelse.com/image.jpg";
}
}, fileRequest);
}
the problem is that it is very slow, it takes sometimes 2 minutes+ to load every image (although the UI remains responsive, and everything else is displayed immediately in the listbox, apart from the images)
am I doing something wrong? can i get it to run faster?
EDIT:
I tried using the imagefailed event and replace the link, no improvement at the speed of loading the pics
What I have done to avoid this problem in my application is, I have loaded the items with a default Image, The image source is binded to a property in my result item of type ImageSource. By default it returns the default image. After processing or download completion the imagesource value changes to the new Image triggering the NotifyPropertyChanged event and hence it is automatically reflected on the UI. I hope it helps you.
I have a HP Scanjet 7000 (duplex & ADF scanner) and a HP Scanjet 5500c (only ADF) and a scanner program I'm developing which uses WIA 2.0 on Windows 7.
The problem is that the code works perfectly on the older scanner model, but on the newer one the code seems to run just fine through the first page, then fail on the second. If I step through the code around the following line;
image = (WIA.ImageFile)wiaCommonDialog.ShowTransfer(item, wiaFormatTIFF, false);
the old scanner stops and waits for another call to be made on the same reference, but the newer one just runs through all it's pages from the feeder in one continuous operation.
I notice if I'm using the default scanning program in Windows 7, the newer one returns a single .tif file which contains all the separate pages. The older one returns separate .jpg files (one for each page).
This indicates to me that the newer scanner is scanning through its whole feeder before it is ready to return a collection of images where the older one returns ONE image between each page scanned.
How can I support this behavior in code? The following is part of the relevant code which works on the older scanner model:
public static List<Image> Scan(string scannerId)
{
List<Image> images = new List<Image>();
List<String> tmp_imageList = new List<String>();
bool hasMorePages = true;
bool useAdf = true;
bool duplex = false;
int pages = 0;
string fileName = null;
string fileName_duplex = null;
WIA.DeviceManager manager = null;
WIA.Device device = null;
WIA.DeviceInfo device_infoHolder = null;
WIA.Item item = null;
WIA.ICommonDialog wiaCommonDialog = null;
manager = new WIA.DeviceManager();
// select the correct scanner using the provided scannerId parameter
foreach (WIA.DeviceInfo info in manager.DeviceInfos)
{
if (info.DeviceID == scannerId)
{
// Find scanner to connect to
device_infoHolder = info;
break;
}
}
while (hasMorePages)
{
wiaCommonDialog = new WIA.CommonDialog();
// Connect to scanner
device = device_infoHolder.Connect();
if (device.Items[1] != null)
{
item = device.Items[1] as WIA.Item;
try
{
if ((useAdf) || (duplex))
SetupADF(device, duplex); //Sets the right properties in WIA
WIA.ImageFile image = null;
WIA.ImageFile image_duplex = null;
// scan image
image = (WIA.ImageFile)wiaCommonDialog.ShowTransfer(item, wiaFormatTIFF, false);
if (duplex)
{
image_duplex = (ImageFile)wiaCommonDialog.ShowTransfer(item, wiaFormatPNG, false);
}
// save (front) image to temp file
fileName = Path.GetTempFileName();
tmp_imageList.Add(fileName);
File.Delete(fileName);
image.SaveFile(fileName);
image = null;
// add file to images list
images.Add(Image.FromFile(fileName));
if (duplex)
{
fileName_duplex = Path.GetTempFileName();
tmp_imageList.Add(fileName_duplex);
File.Delete(fileName_duplex);
image_duplex.SaveFile(fileName_duplex);
image_duplex = null;
// add file_duplex to images list
images.Add(Image.FromFile(fileName_duplex));
}
if (useAdf || duplex)
{
hasMorePages = HasMorePages(device); //Returns true if the feeder has more pages
pages++;
}
}
catch (Exception exc)
{
throw exc;
}
finally
{
wiaCommonDialog = null;
manager = null;
item = null;
device = null;
}
}
}
device = null;
return images;
}
Any help on this issue would be very much appreciated! I can't seem to find a working solution on the web. Just unanswered forum posts from people with the same problem.
we had a very similar problem and various solutions, e.g. by setting certain properties, did not help. The main problem was that the scanner (ADF) retracted all pages on startup, regardless of what was happening in the program code.
The process repeatedly led to errors, since "too much" was made before the next page was scanned. This applies in particular to the fact that another "Connect" was attempted.
For this reason, we have modified the code so that the individual pages can be read in as quickly as possible:
public List<Image> Scan(string deviceID)
{
List<Image> images = new List<Image>();
WIA.ICommonDialog wiaCommonDialog = new WIA.CommonDialog();
WIA.Device device = this.Connect(deviceID);
if (device == null)
return images;
WIA.Item item = device.Items[1] as WIA.Item;
List<WIA.ImageFile> wiaImages = new List<ImageFile>();
try
{
// scan images
do
{
WIA.ImageFile image = (WIA.ImageFile)wiaCommonDialog.ShowTransfer(item, wiaFormatJPEG, false);
wiaImages.Add(image);
} while (true);
}
catch (System.Runtime.InteropServices.COMException ex)
{
if ((uint)ex.ErrorCode != WIA_PROPERTIES.WIA_ERROR_PAPER_EMPTY)
throw ex;
}
catch (Exception ex)
{
throw ex;
}
foreach (WIA.ImageFile image in wiaImages)
this.DoImage(images, image);
return images;
}
I see you're calling a method called SetupADF, which is not shown, that presumably sets some properties on the device object. Have you tried setting WIA_DPS_PAGES (property 3096) and/or WIA_DPS_SCAN_AHEAD_PAGES (property 3094)?
I have a blog post about scanning from an ADF in Silverlight, and I believe a commenter came up against the same issue you're having. Setting WIA_DPS_PAGES to 1 fixed it for him. I ended up modifying my code's SetDeviceProperties method to set WIA_DPS_PAGES to 1 and WIA_DPS_SCAN_AHEAD_PAGES to 0.
After alot of trial and error I stumbled upon a solution which worked for reasons I'm not quite sure of. It seems like the ShowTransfer() method was unable to convert the page to .png or .tiff WHILE scanning. Setting the format to JPEG or BMP actually solved the issue for me:
image = (ImageFile)scanDialog.ShowTransfer(item, wiaFormatJPEG, false);
I think I saw somewhere on the web that this method actually returns BMP regardless of the format specified. Might be that converting the image to png or tiff is too heavy as opposed to using bmp or jpeg.
On a sidenote, I'm setting the property setting: 3088 to 0x005 (adf AND duplex mode).