This is the code I'm using to create the Image that I'm inserting into a FlowDocument.
private static Image GetImage(string url)
{
if (url == null) throw new ArgumentNullException("url");
if (!(url.StartsWith("http://") || url.StartsWith("https://") || url.StartsWith("ftp://")))
return null;
var uri = new Uri(url, UriKind.Absolute);
var bmpImg = new BitmapImage(uri)
{
CacheOption = BitmapCacheOption.OnDemand,
};
if (bmpImg.CanFreeze) bmpImg.Freeze();
var img = new Image
{
Source = bmpImg,
Stretch = Stretch.Uniform,
Height = 120,
Width = 120,
};
return img;
}
When I create a document and insert an image from my server with
Designer.CaretPosition.Paragraph.Inlines.Add(image);
everything works fine - image displays as expected. Also, the main Google Logo image works fine, but the HackaDay Logo and others just display a blank image.
What could be the reason for this?
I think that some websites have hotlink protection. For example in my website I can link a photo in every page that it is in my domain and it works well, however if you try to link a photo in other domain, the photo doesn't load.
Related
I want to get rendered height and width of the image before loading so I have created an object of image and trying to get height, width by onload method.
Below is my code snippet:
var imgUrl = "https://www.sammobile.com/wp-content/uploads/2019/03/keyguard_default_wallpaper_green-405x405.png";
var imgHeight = 0;
var imgWidth = 0;
var Im = new Image();
Im.src = imgUrl;
Im.onload = () => (imgHeight = Im.height);
But I am getting an error while creating the image object.
Image is not a constructor
How can I investigate this?
I don’t have enough points to comment but there is nothing wrong with your snippet.
checked browser compatibility and it’s very good.
You don’t have this API for some reason, might worth check your bundler for answers.
As pointed out by #mstrk there's nothing wrong with your script, however, if your runtime (your browser) somehow doesn't know how to construct the image via new Image() you can create one via
document.createElement('img')
Here's the snippet printing width / height in the console when image loads
var imgUrl = "https://www.sammobile.com/wp-content/uploads/2019/03/keyguard_default_wallpaper_green-405x405.png";
var imgHeight = 0;
var imgWidth = 0;
var Im = document.createElement('img');
Im.src = imgUrl;
Im.onload = () => {
imgHeight = Im.height;
imgWidth = Im.width;
console.log(imgWidth, imgHeight);
}
I tried to put an AutoCompleteTextField (used for address completion) and a Google Map peer component (using the cn1lib) in the same container, but it doesn’t work fine on real device (it's ok only in the Simulator).
Using a BoxLayout.y, the completion list appears only on iPhone but not on Android.
Using a BorderLayout.totalBelow, with Google Map in the center and the AutoCompleteTextField on the north, after selecting an address from the autocompletion list, the AutoCompleteTextField disappears (tested on iPhone).
Could you please give me any hint to make the two components working correctly? The cn1lib I’m using is updated. Thank you
Container innerContent = new Container(BorderLayout.totalBelow());
// Start content
AutoCompleteTextField autoCompleteTextField = (AutoCompleteTextField) InputUtilities.getAutoCompleteAddress(true);
autoCompleteTextField.setUIID("BaseStructureForm-InnerBoxMap");
// Google Map
final MapContainer googleMap = new MapContainer() {
#Override
public Dimension calcPreferredSize() {
int width = contentBox.getWidth() - CN.convertToPixels(10, true);
int height = CN.convertToPixels(50, false);
return new Dimension(width, height);
}
};
innerContent.add(BorderLayout.NORTH, autoCompleteTextField);
innerContent.add(BorderLayout.CENTER, googleMap);
// End content
autoCompleteTextField.addListListener(e -> {
String selectedItem = (String) ((com.codename1.ui.List) e.getSource()).getSelectedItem();
String place_id = (String) autoCompleteTextField.getClientProperty("place_id");
//googleMap.setCameraPosition(new Coord(43.0511, 10.8892274));
GoogleMapUtilities.setMapPlace(place_id, (latitudine, longitude) -> {
googleMap.zoom(new Coord(latitudine, longitude), 3);
});
});
I have a button that has an image from the gallery. The image is scaled to the display width and its height is set to half the display width. Now when I upload this image to the server, I send the imagePath which results in sending the orginal image of the gallery. How can I upload the icon of the button? (ie. width = display width and height = half of the display width)
getImageButton.addActionListener(f -> {
Display.getInstance().openGallery(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
try {
if (evt == null) {
return;
}
imagePath = (String) evt.getSource();
Image i = Image.createImage(imagePath);
Image profileImgg = i.scaledWidth(Display.getInstance().getDisplayWidth());
getImageButton.setIcon(profileImgg);
getImageButton.setPreferredH((Display.getInstance().getDisplayWidth()/2)-50);
getImageButton.getParent().revalidate();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}, Display.GALLERY_IMAGE);
});
PS. I want to upload the icon of the button, not the image in the gallery.
The scaled method produces a new image instance it doesn't impact the file from which you loaded. Also this approach to scaling would distort the image aspect ratio. I would suggest a more sensible scaling strategy such as fill().
You have two options:
Convert the loaded image to a file object. The easy way is:
EncodedImage e = EncodedImage.createFromImage(img, true);
byte[] theDataOfTheImageFile = e.getImageData();
Transform the file directly using the ImageIO API
I created thumbnails based on ListView control. On ListView.ItemSource I bind ObservableColletion<Photos> Photos{get;set}.
I create thumbnail images in another threads also in parallel way.
I simplified my code.
public class ThumbnailCreator
{
public static List<Photos> CreateThumbnailImage(List<Photos> photos)
{
var thumbnails = new List<Photos>();
Parallel.ForEach(photos, photo =>
{
var bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.DecodePixelHeight = 128;
bitmap.DecodePixelWidth = 128;
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.CreateOptions = BitmapCreateOptions.DelayCreation;
bitmap.UriSource = new Uri(photo.FullPath);
bitmap.EndInit();
if (bitmap.CanFreeze)
bitmap.Freeze();
thumbnails.Add(new Photos{ThumbnailImage = bitmap});
});
return thumbnails;
}
}
Problem is here:
//I break binding before I start refreshing thumbnails
this.Thumbnails.ItemsSource = null;
//load files from folder
List<Photos> photos = _fileManager.LoadFromDir(folderBrowserDialog.SelectedPath);
//create thumbnail images in another threads, not on UI
List<Photos> thumbnails = ThumbnailCreator.CreateThumbnailImage(photos);
//create new source
Photos = new ObservableCollection<Photos>(thumbnails);
//reenable binding, this part of code cause that UI free
this.Thumbnails.ItemsSource = Photos;
When I reenable binding UI freeze, I tried use dispatcher but result is same UI freeze.
this.Dispatcher.Invoke(DispatcherPriority.SystemIdle, new Action(() =>
{
Photos = new ObservableCollection<Photos>(thumbnails);
this.Thumbnails.ItemsSource = Photos;
}));
How can I avoid freeze UI?
EDITED:
I edited my code based on Dean K. advice. I dont break bind before update source of listview.
I updated source of ListView.ItemSource via Dispatcher:
Sync Invoke:
App.Current.Dispatcher.Invoke(new Action(() =>
{
thumbnails.Add(new Photos { ThumbnailImage = bitmap });
}), DispatcherPriority.ContextIdle);
Result - UI behavior.
Images are being added continuously but if collection contains more than 500 images at the and WPF window freezes. For example it is not possible move window, scroll listview.
Async Invoke
App.Current.Dispatcher.InvokeAsync(new Action(() =>
{
thumbnails.Add(new Photos { ThumbnailImage = bitmap });
}), DispatcherPriority.ContextIdle);
Result - UI behavior.
At start app freezes but after several seconds images are being added continously and also is it possible move window, scroll listview.
So my question is what is root of problem that app freezes ? How can I avoid this behaviour. I upload sample application.
Don't break the binding before adding items to the ObservableCollection.
Bind Thumbnails.ItemsSource to Photos OC and than on another thread load and add items to Photos OC. That way your UI will not freeze.
You might want to use the multithreaded ObservableColleciton you can find on code project. Search for ObservableCollectionMt...
Try to create a image in code as below:
sp = new StackPanel() { Orientation = Orientation.Horizontal };
Image myImage = new Image() { HorizontalAlignment = HorizontalAlignment.Left, Width = 16, Height = 16, Margin = new Thickness(1, 0, 0, 0) };
MyImage.Source = new BitmapImage(new Uri("/MyAssembly;component/folder/image1.png", UriKind.RelativeOrAbsolute));
sp.Children.Add(MyImage);
then run the app, the image does not display. Check the data with Fiddler and got 404 error. The source for above image is something like:
http://localhost:80/MyAssembly;component/folder/image1.png
but this image is complied into an assembly MyAssembly.
It is okay to get the image xaml from the assembly with following markup:
<Image Source="/MyAssembly;component/folder/image1.png"/>
Confused. Not sure why. How to get dynamic image in code?
Updated: Thanks for information form Clemens. Try following code:
sp = new StackPanel() { Orientation = Orientation.Horizontal };
ImageSourceConverter converter = new ImageSourceConverter();
Image myImage = new Image() { HorizontalAlignment = HorizontalAlignment.Left, Width = 16, Height = 16, Margin = new Thickness(1, 0, 0, 0) };
MyImage.Source = (ImageSource)converter.ConvertFromString("/MyAssembly;component/folder/image1.png");
sp.Children.Add(MyImage);
the result same as before. message from Fiddler:
The resource you are looking for has been removed, had its name changed, or is temporarily unavailable.
The resource for this still is
http://localhost:80/MyAssembly;component/folder/image1.png.
Don't know what scheme to use for that Uri in Silverlight, where you would write something like pack://application,,,/MyAssembly;component/folder/image1.png in WPF.
But fortunately you could always write this:
ImageSourceConverter converter = new ImageSourceConverter();
MyImage.Source = (ImageSource)converter.ConvertFromString(
"/MyAssembly;component/folder/image1.png");
It is of course also possible to explicitly set a relative URI:
MyImage.Source = new BitmapImage(
new Uri("/MyAssembly;component/folder/image1.png", UriKind.Relative));
Note however that the Build Action for image1.png has to be set to Resource in any case.