Can't retrieve image from web in Xamarin forms - c#

In the viewmodel of my page, I try to get an image to show. This image I get from one of our webservice. The image source is stored in ProductImage
string path = $#"http://www.MyCompany.be/cdn-cgi/image/width=150,quality=75/images/products/{CurrentProduct.Image}".Replace($"\\", $"/");
ProductImage = ImageSource.FromUri(new Uri(path));
I of course make sure when I update the Image source for the view when I change it
public ImageSource ProductImage
{
get
{
return _productImage;
}
set
{
if (_productImage != value)
{
_productImage = value;
OnPropertyChanged();
}
}
}
Sadly, for some reason it doesn't work. I checked the URL called and it does lead to an image.
It used to work when I was using streams instead of calling an URL. I know I haven't put the safety checks around yet to make sure the image exist, but other than that nothing has changed. I save the image the exact same way, i just use fromUri rather than fromStream.
//Get target's SmbFile.
var file = new SmbFile(path, auth);
try
{
if (file.Exists())
{
// Get readable stream.
var readStream = file.GetInputStream();
//Create reading buffer.
MemoryStream memStream = new MemoryStream();
//Get bytes.
((Stream)readStream).CopyTo(memStream);
var stream1 = new MemoryStream(memStream.ToArray());
if (stream1.Length < 30000000)
{
//Save image
//ProductImage = ImageSource.FromStream(() => stream1);
//Dispose readable stream.
readStream.Dispose();
InfoColSpan = 1;
}
else
{
Common.AlertError("Image trop lourde pour l'affichage");
}
}
}
catch (Exception ex)
{
Common.AlertError(ex, "Impossible de charger l'image");
}
Since I changed my method, I no longer load anything.

Related

Save an Image with superimposed Label on the device

I have some images in my ftp web space, and through this method I can view them on the screen, and above them I insert a Label.
var ImageUrl = "ftp://xxxxxxxxx.jpg";
//Download Image
byte[] ImgByte1 = WebClient.DownloadData(ImageUrl);
MemoryStream mStream1 = new MemoryStream(ImgByte1);
ObservableCollection<FraseClass> listFrasi = new ObservableCollection<FraseClass>
{
new FraseClass{Source=ImageSource.FromStream(() => mStream1)},
}
XAML
<Image
Source="{Binding Source}"/>
<Label
Text="Hello"/>
I am looking for a way to be able to save the image on the device with the text superimposed. I tried to search but couldn't find anything to fix my problem
I am looking for a way to be able to save the image on the device with the text superimposed. I tried to search but couldn't find anything to fix my problem
According to your description, you want to save image that downloadind from url into local storage, am I right?
If yes, I suggest you can use Xamarin.Forms DependencyService to do this.
Firstly, create an interface in shared code.
public interface IImageFile
{
void SaveImage(string name, byte[] data, string location = "temp");
}
Then implement the interface on Android platform. Don't forget to register the platform implementations.
[assembly: Dependency(typeof(ImageFile))]
namespace FormsSample.Droid
{
public class ImageFile : IImageFile
{
public void SaveImage(string name, byte[] data, string location = "temp")
{
var documentsPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
documentsPath = System.IO.Path.Combine(documentsPath, "Orders", location);
Directory.CreateDirectory(documentsPath);
string filePath = System.IO.Path.Combine(documentsPath, name);
using (FileStream fs = new FileStream(filePath, FileMode.OpenOrCreate))
{
int length = data.Length;
fs.Write(data, 0, length);
}
}
}
}
Finally, resolving platform implementations with the DependencyService
private void btn1_Clicked(object sender, EventArgs e)
{
var ImageUrl = "ftp://xxxxxxxxx.jpg";
//Download Image
byte[] ImgByte1 = WebClient.DownloadData(ImageUrl);
DependencyService.Get<IImageFile>().SaveImage("ImageName.jpg", ImgByte1, "imagesFolder");
}
you need to add permission WRITE_EXTERNAL_STORAGE and READ_EXTERNAL_STORAGE in AndroidMainfeast.xml, then you also need to Runtime Permission Checks in Android 6.0. Using the following code in Mainactivity.cs to request permissions.
private void checkpermission()
{
if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.WriteExternalStorage) == (int)Permission.Granted)
{
// We have permission, go ahead and use the writeexternalstorage.
}
else
{
// writeexternalstorage permission is not granted. If necessary display rationale & request.
}
if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.ReadExternalStorage) == (int)Permission.Granted)
{
// We have permission, go ahead and use the ReadExternalStorage.
}
else
{
// ReadExternalStorage permission is not granted. If necessary display rationale & request.
}
}
Detailed info about IOS platform, you can take a look:
How to download image and save it in local storage using Xamarin-Forms.?
Update:
If you want to add text watermark on image, you need to convert byte[] to bitmap to add text firstly.
Android.Graphics.Bitmap mutableBitmap;
Android.Graphics.Bitmap bitmap;
public void ConvertImage(byte[] imageArray)
{
bitmap = BitmapFactory.DecodeByteArray(imageArray, 0, imageArray.Length);
}
public void Watermark()
{
mutableBitmap = bitmap.Copy(Android.Graphics.Bitmap.Config.Argb8888, true);
Canvas canvas = new Canvas(mutableBitmap);
// Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
paint.Color = Android.Graphics.Color.Black;
paint.TextSize = 50;
canvas.DrawText("hellod world", 50, 50, paint);
}
Then convert bitmap into byte[] to save image into local storage.
public void convertbitmap(Bitmap bitmap)
{
bitmap = mutableBitmap;
MemoryStream stream = new MemoryStream();
bitmap.Compress(Bitmap.CompressFormat.Png, 0, stream);
byte[] bitmapData = stream.ToArray();
}

How do I retrieve image properly using ParseFile?

I'm using the following code to save an image
ParseFile file = null;
if (ProfileImage != null && ProfileImage.ContentLength > 0 && !string.IsNullOrEmpty(ProfileImage.FileName))
{
byte[] fileBytes = new byte[ProfileImage.ContentLength];
file = new ParseFile(ProfileImage.FileName, fileBytes);
await file.SaveAsync();
var player = new ParseObject("Player");
if(file != null)
{
player["ProfilePic"] = file;
}
await player.SaveAsync();
}
I'm trying to retrieve the image so I can display using the following code
ParseObject player = Task.Run(() =>
ParseObject.GetQuery("Player").WhereEqualTo("objectId", id).FirstOrDefaultAsync()).Result;
ParseFile profileImage = null;
string profileImageUrl = "";
if (player.ContainsKey("ProfilePic"))
{
profileImage = player.Get<ParseFile>("ProfilePic");
profileImageUrl = profileImage.Url.AbsoluteUri;
}
profileImageUrl have a correct url such as http://files.parsetfss.com/c8db8833-b04b-4877-8040-b70df1ec216c/tfss-11c442f3-6146-4316-a6c0-7c9a063d897e-Koala.jpg
However, the image is always broken. I'm trying to display the image using html tag and the image is always broken.
Your example image contains 762Kb of zero-bytes. I can't really see in your save method that you actually put content in the array either.
byte[] fileBytes = new byte[ProfileImage.ContentLength];
file = new ParseFile(ProfileImage.FileName, fileBytes);
await file.SaveAsync();
The code above creates an empty array of x bytes long and then you save it. You should put the picture bytes in there somehow. I can't tell from your code what type the ProfileImage object is, but i suppose you can get the content bytes from that object.

Write a part of the class as XML

Hello, I would like to ask you a question.
I created a Person class and I wrote persons name, surname, id and image.
Now I want to save this class as .xml with image. I found a solution for the save a class as .xml but it does not save any image into .xml file.
private void SaveasXML()
{
XmlSerializer serializer = new XmlSerializer(typeof(BindingList<Person>));
FileStream fileStream = File.Create(Application.StartupPath + "\\Data\\Person.xml");
serializer.Serialize(fileStream, New_Xml_Person);
}
I want to save all information with image into .xml file. To save image as .xml file it should be converted to base64string. I know that but I could not use it.
Any suggestions? Thanks.
You can add a byte[] ImageBuffer property to your Person class, which contains the binary image data. You would then also set the XmlIgnore attribute on the Image property to suppress its (de)serialization, and set XmlElement("Image") on the ImageBuffer properties to (de)serialize it as Image.
Updated answer:
[XmlIgnoreAttribute()]
public Bitmap Picture { get { return picture; } set { picture = value; } }
[XmlElementAttribute("Picture")]
public byte[] PictureByteArray {
get {
if (picture != null) {
using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
      {
     picture.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
          return ms.ToArray();
      }
} else return null;
}
set {
if (value != null)
{
using (System.IO.MemoryStream ms = new System.IO.MemoryStream(value))
      {
           picture = new Bitmap(Image.FromStream(ms));
      }
}
else picture = null;
}
}

Cannot deserialize Image after sending it through the network

So, I have these two methods, which I am using to serialize and deserialize Images:
private static Image GetImageFromString(string image)
{
using (var stream = new MemoryStream(Convert.FromBase64String(image)))
{
return Image.FromStream(stream);
}
}
private static string GetImageAsString(Image image)
{
using (var stream = new MemoryStream())
{
image.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg);
return Convert.ToBase64String(stream.GetBuffer());
}
}
If I do something Like this:
public Form1()
{
InitializeComponent();
var image = Image.FromFile(#"F:\phpide.png");
pictureBox1.Image = image;
var serialized = GetImageAsString(image);
var secondImage = GetImageFromString(serialized);
pictureBox2.Image = secondImage;
}
It works as expected
Although, If I do something like this:
//client
public void GetImage(JObject o)
{
var imageFile = o["file"].ToString();
if (!File.Exists(imageFile))
{
SendMessage("File does not exist");
return;
}
using (var image = Image.FromFile(imageFile))
{
var serialized = GetImageAsString(image);
var ob = new JObject
{
{ COMMAND, (int) Command.GetImage },
{ "content", serialized }
};
Send(ob);
ob = null;
serialized = null;
}
}
//server
public void ReceiveImage(JObject o)
{
var content = o["content"].ToString();
var image = GetImageFromString(content);
var form = new ImagePreviewForm(image);
form.Show();
}
//server
public ImagePreviewForm(Image image)
{
InitializeComponent();
pictureBox1.Image = image;
}
The image is just blank.
I have checked and the image is being received correctly, with no data loss.
What could be going wrong here? Where should I look?
This is at least one problem:
return Convert.ToBase64String(stream.GetBuffer());
You shouldn't use MemoryStream.GetBuffer here - you should use ToArray. The GetBuffer method returns the underlying buffer as-is... complete with junk data at the end of the buffer, beyond the logical current length of the stream.
Additionally, you shouldn't close the stream when you call Image.FromStream. From the docs:
You must keep the stream open for the lifetime of the Image.
So get rid of the using statement in GetImageFromString.
With the using statement you are disposing the image before the UI thread can display the image properly. Take the code out of the using block and add a Dispose() statement to the Form.Close() method.

Imagestream to file resulting in partially gray image (sometimes)

I having an issue uploading / sending images from a stream to a generic handler in ASP.NET. I’ve build a windows phone app that can take an image and send it to the generic handler on my website.
Unfortunately in some occasions the image turns out to be (partially) gray. I think it might have something to to with a lost/bad internet connection of the mobile device. This problem happens every 50 images or so.
When the faulty image is send I do not get an error of any kind. I’m looking for two possible solutions.
How do i prevent the windows phone uploading a partially gray image to the generic handler.
How do i check if an image is partially gray on the server so can send a error message back to the phone.
to make this question more compleet I included the code of the generic handler and an example image. Second I’m very curious why this occus. TCPIP has an handshake so above isseu should not be possible ?
public class UploadImages : IHttpHandler
{
private IWorkOrderRepository _workOrderRepository;
private IDigitalFileRepository _digitalFileRepository;
private IUserRepository _userRepository;
public UploadImages()
{
_workOrderRepository = ((Global)HttpContext.Current.ApplicationInstance).Kernel.Get<IWorkOrderRepository>();
_digitalFileRepository = ((Global)HttpContext.Current.ApplicationInstance).Kernel.Get<IDigitalFileRepository>();
_userRepository = ((Global)HttpContext.Current.ApplicationInstance).Kernel.Get<IUserRepository>();
}
public void ProcessRequest(HttpContext context)
{
var cookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
var user = (Domain.Users.User)HttpContext.Current.User;
string WorkOrderId = context.Request.QueryString["workOrderId"];
string latitude = context.Request.QueryString["LATITUDE"];
string Longitude = context.Request.QueryString["LONGITUDE"];
if (latitude != "0" && Longitude != "0")
{
string file = "Filename.jpg";
string uploadPath = context.Server.MapPath("~/Temp/");
using (var stream = new MemoryStream())
{
var image = ImageResizer.Resize(Image.FromStream(context.Request.InputStream), 700);
image.Save(stream, ImageFormat.Jpeg);
stream.Position = 0;
var workOrder = _workOrderRepository.GetAll(x => x.Id == Convert.ToInt32(WorkOrderId)).FirstOrDefault();
workOrder.AddPhoto(_workOrderRepository, _digitalFileRepository, new AuditInfo((Domain.Users.User)user), stream, file, "image/jpeg", Convert.ToDouble(latitude), Convert.ToDouble(Longitude));
}
}
else
{
string file = "Filename.jpg";
string uploadPath = context.Server.MapPath("~/Temp/");
using (var stream = new MemoryStream())
{
var image = ImageResizer.Resize(Image.FromStream(context.Request.InputStream), 700);
image.Save(stream, ImageFormat.Jpeg);
stream.Position = 0;
var workOrder = _workOrderRepository.GetAll(x => x.Id == Convert.ToInt32(WorkOrderId)).FirstOrDefault();
workOrder.AddPhoto(_workOrderRepository, _digitalFileRepository, new AuditInfo((Domain.Users.User)user), stream, file, "image/jpeg");
}
}
}
public bool IsReusable
{
get
{
return false;
}
}
}

Categories