I'm trying to implement a Windows Phone 8 App that works with image handling, trying it to port it from a Windows 8 App. But I got stuck quite quickly, at the beginning.
What I want to achieve is to select some pictures from the phone and show them in my app, in a similar way they look in an album. For this, I've tried some MVVM technique, also. But I'm given an error when I'm trying to create a BitmapImage from the file Stream saying I'm out of range...
Here's my model :
public class SelectedPhoto : IDisposable
{
public Stream Data { get; set; }
public string Name { get; set; }
public BitmapImage Image { get; set; }
public SelectedPhoto(string name, Stream data)
{
Name = name;
Data = new MemoryStream();
data.CopyTo(Data);
Image = new BitmapImage();
Image.SetSource(Data); //Here's the Argument Exception.
}
public void Dispose()
{
Data.Dispose();
}
}
So I'm given the exception quite in the constructor... and I use this in code in a PhotoChooserTask like this :
private void PhotoChooserTaskCompleted(object sender, PhotoResult e)
{
if (e.TaskResult == TaskResult.OK)
{
PhotosViewModel.AddPhoto(new SelectedPhoto(e.OriginalFileName, e.ChosenPhoto));
}
}
The Argument Exception says : Offset and length were out of bounds for the array or count is greater than the number of elements from index to the end of the source collection. But I'm not manipulating the Stream in any way, I just need it as it is to create the BitmapImage from it, as I've looked after some examples.
How can I get the BitmapImage of a selected image file from phone in this case? Or much better, how can I get it directly as a WriteableBitmap? Because later on, I'm planning on doing some pixel manipulation.
Any type of approach is welcome, thank you.
To fix your code, call the Seek method to go back to the beginning of your stream:
public SelectedPhoto(string name, Stream data)
{
Name = name;
Data = new MemoryStream();
data.CopyTo(Data);
Data.Seek(0, SeekOrigin.Begin);
Image = new BitmapImage();
Image.SetSource(Data); //Here's the Argument Exception.
}
That said, why are you duplicating the stream? You could directly use data.
Related
I'm trying to display an Image for an object in a table view, I have created a DisplayModel class in order to display the relevant values in the table columns from an observable collection, I have 2 columns containing string values and one integer all of which are displaying fine, I also have an image of the Car I wish to display but it will only display the Image#Hashcode rather than the image itself.
The implementation I currently have is as follows:
The display model class:
private ObjectProperty<Image> image;
private SimpleStringProperty make;
private SimpleStringProperty model;
private SimpleDoubleProperty price;
public DisplayModel(Image image, String make, String model, Double price) {
this.image = new SimpleObjectProperty<>(image);
this.make = new SimpleStringProperty(make);
this.model = new SimpleStringProperty(model);
this.price = new SimpleDoubleProperty(price);
}
public Image getImage() {
return image.get();
}
public void setImage(Image displayImage) {
this.image = new SimpleObjectProperty<>(displayImage);
}
The implementation in the initialise method on the controller for the FXML file:
try {
OutputStream targetFile = new FileOutputStream(s + "\\" + imageUrl);
targetFile.write(fileBytes);
targetFile.close();
File f = new File(s + imageUrl);
image = new Image(f.toURI().toString());
} catch (IOException e) {
e.printStackTrace();
}
Using the ImageView controller and trying to display the same image presents it fine so I'm wondering whether it's do with the ObjectProperty implementation or the TableView control.. I've recently faced a similar and far more common issue of needing to override the toString method to return the actual value rather than the String#HashValue, I wonder whether there is a similar way to resolve this issue.
Any advice would be greatly appreciated, thanks for your time.
This has to do with the updateItem implementation of the TableCell returned by the default cellFactory. This is implemented as follows (ignoring empty cells):
If the item is a Node, display it using setGraphic with the item as parameter. This adds the Node to the scene inside the TableCell.
Otherwise convert the object to text using it's toString method and use setText to display the resulting value as text in the TableCell.
Image is not a subclass of Node; therefore you get the latter behavior.
To change this behavior, you need to use a custom cellFactory that deals with the item type properly:
ItemImage.setCellFactory(col -> new TableCell<Item, Image>() { // assuming model class named Car here; type parameters match the TableColumn
private final ImageView imageView = new ImageView();
{
// set size of ImageView
imageView.setFitHeight(50);
imageView.setFitWidth(80);
imageView.setPreserveRatio(true);
// display ImageView in cell
setGraphic(imageView);
}
#Override
protected void updateItem(Image item, boolean empty) {
super.updateItem(item, empty);
imageView.setImage(item);
}
});
Note that usually you don't keep the graphic for empty cells. I decided to do this in this case to keep the cell size consistent.
Does Entity Framework incorrectly detect changes to images?
I have a "Person" entity class defined as follows;
public class Person
{
public int Id { get; set; }
public byte[] Photo { get; set; }
}
I have bound the Photo to a PictureBox control on my form using a datasource.
There form also uses a dynamically created bindingNavigator.
I also have written an audit log to populate captured changes
The procedure calls the ObjectContext DetectChanges() and then
var entries = ObjectContext.ObjectStateManager.GetObjectStateEntries()
Which contains an entry showing that the Photo has been modified.
entry.OriginalValues[name] matches entry.CurrentValues[name]
The Column is varbinary(MAX) in SQL Server and the size of the picture files I have loaded are under 1Mb
If I set all of the columns to null the error no longer occurs
The code I use to get the file is
private void LoadPhotoButton_Click(object sender, EventArgs e)
{
using (var dlg = new OpenFileDialog())
{
dlg.Filter = "JPEG files |*.jpg";
if (dlg.ShowDialog() == DialogResult.OK)
{
PhotoPictureBox.Image = Image.FromFile(dlg.FileName);
}
}
}
I note here that hex zero can be inserted as padding characters when these fields are involved in string conversion.... could the binding be doing that somehow?
If I delete the picturebox from the form, or even bind the control as a text box instead of a picturebox then the behaviour is correct ( not that a picture bound to a text box is any use )
I am able to work around the problem by not binding directly to the picture box.
Instead I just load it on the BindingSource_CurrentChanged event using
private void BindingSource_CurrentChanged(object sender, EventArgs e)
{
var obj = (Person) BindingSource.Current;
this.PictureBox.Image = byteArrayToImage( obj.Photo);
}
public Image byteArrayToImage(byte[] byteArrayIn)
{
MemoryStream ms = new MemoryStream(byteArrayIn);
Image returnImage = Image.FromStream(ms);
return returnImage;
}
I am using my work around - documented at the end of the question as a make do answer.
I'm confused about how should I do a model that has some uploaded file, like for exemplo:
User has photos.
I already found out how to upload a file, but the question here is about what to do with the file that was now uploaded, how can I link this new uploaded file(photo in the exemple) with a model(the user in the example).
Thanks.
OBS: Using play for Java here, not Scala.
You have to link your User to his picture. For that, your best option is to use the User id, which should be unique.
Then, if you uploaded your photo under the pictures/user folder in your filesystem, then you should save the picture as pictures/user/USER_ID.png (png or jpg or anything else).
Then, you can have an action which retrieve the picture according to the user id:
public static Result picture(String userId) {
Picture picture = Picture.findPicture(userId);
if (picture != null) {
response().setContentType(picture.contentType);
return ok(picture.bytes);
}
return notFound();
}
And the Picture class looks like:
public class Picture {
public byte[] bytes;
public String contentType;
public static Picture findPicture(String userId) {
String[] extensions = {"png","jpg"}; // an enum should be better
for (String extension:extensions) {
String path = "pictures/user/" + userId + "." + extension;
if (new File().exists(path)) {
Picture picture = new Picture();
picture.bytes = IOUtils.toByteArray(new FileInpustream(path));
picture.contentType = findContentType(extension);
return picture;
}
}
return null;
}
protected static String findContentType(String extension) {
if (extension.equalsIgnoreCase("jpg") {
return "image/jpeg";
} else if (extension.equalsIgnoreCase("png") {
return "image/png";
}
}
}
I did something similar once (but the pictures were stored in memory), you can take a look here.
Just create a convention if user has only one picture. Per instance, if your user was registered in 2012-07-23 and has id = 100, move the file to some place mapped from these data:
/uploaded-dir/2012/07/23/100/picture.jpg
After that, you can use the same convention to read the file.
I am trying to retrieve multiple images from isolated storage using listbox but i am not sure why it just only retrieve the lastest image from isolated storage.Therefore hope anyone could help me make amends to my code or could provide me with sample code that works which is about the same as mine.Thanks.
My code :
private void LoadFromLocalStorage(string imageFolder, string imageFileName )
{
var isoFile = IsolatedStorageFile.GetUserStoreForApplication();
if (!isoFile.DirectoryExists(imageFolder))
{
isoFile.CreateDirectory(imageFolder);
}
string filePath = Path.Combine(imageFolder, imageFileName);
using (var imageStream = isoFile.OpenFile(filePath, FileMode.Open, FileAccess.Read))
{
var imageSource = PictureDecoder.DecodeJpeg(imageStream);
BitmapImage bi = new BitmapImage();
ListBoxItem item = new ListBoxItem();
bi.SetSource(imageStream);
item.Content = new Image()
{
Source = bi, MaxHeight = 100, MaxWidth = 100 };
listBox1.Items.Add(item);
}
It would be helpful if you tell what results are you getting.
Do you see only 1 element?
Do you see multiple elements and they are the same?
Do you see multiple elements and only 1 shows a picture and other are empty?
Anyway this is not a proper way to treat listbox. But first things first.
This line doesn't do anything useful:
var imageSource = PictureDecoder.DecodeJpeg(imageStream);
This code should work (it seems), but there may be an error outside the code. How many times this function is called and what parameters are passed - that is what actually matters.
But I would change the code to use Data Binding and proper ItemsSource.
Create class for items
public class MyImage
{
public string FilePath {get; set;}
public ImageSource LoadedSource {get; set;}
}
Create an ObservableCollection<MyImage>() and fill it with your data.
Bind it to ListBox by setting ItemsSource
Design a proper ItemTemplate with Image and Binding:
<Image Source={Binding LoadedSource}/>
This setup will help you debug the issues easily and localize the problem. It is likely that you are calling your original function incorrectly.
Long time lurker, first time poster here.
My question is:
Using C# 2.0, is there a way to associate am image with a class/type such that I don't have to create an instance of the class just to get the image object from that class?
What I am trying to do is scan all the .dlls in my application and construct a list of classes and corresponding attributes. I have this working great, and now I want to somehow associate an image with each class so that I can display a list of classes and have a unique image for each.
I've tried searching SO and the internet for an answer, but can't find anything definite. Any help would be greatly appreciated.
Thanks,
Kyle
You could create an ImageAttribute.
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
class ImageAttribute : Attribute
{
private string ImagePath { get; set; }
public ImageAttribute(string imagePath)
{
ImagePath = imagePath;
}
public Bitmap Image
{
get { return new Bitmap(ImagePath); }
}
}
Or database id, just some way to identify an image.
Figured out how to do it using ideas here and there.
Mark the image as an EmbeddedResource.
Create an attribute for specifying the image name.
Once the image name attribute is read, use the following to locate the image resource inside the assembly where the class was declared:
string[] all = info.Type.Assembly.GetManifestResourceNames();
foreach (string resourceStr in all)
{
if (!String.IsNullOrEmpty(resourceStr) && resourceStr.EndsWith(String.Format(".{0}", iconName), true, CultureInfo.CurrentCulture))
{
Stream file = info.Type.Assembly.GetManifestResourceStream(resourceStr);
if (file != null)
{
info.Icon = Image.FromStream(file);
}
}
}