I have a camerapage which takes a picture, resizes it to a thumbnail and saves this resized image to a file locally on the android phone. I then try to send this uri-string to a viewmodel which is supposed to set its ImageSource property from this uri. I am currently unable to load the image from the url.
Here is my code:
In CameraPage(inside Take photo method)
var documentsPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
using (var imageStream = new MemoryStream())
{
await image.CompressAsync(Bitmap.CompressFormat.Jpeg, 40, imageStream);
image.Recycle();
imageBytes = imageStream.ToArray();
var thumbnail =await DependencyService.Get<IPicResizer>().GetResizedImage(imageBytes);
// Temporary file to store the downloaded image
Java.IO.File tmpFile = new Java.IO.File(documentsPath + "/"+fileName + ".jpg");
tmpFile.ParentFile.Mkdirs();
// String path = MediaStore.Images.Media.InsertImage(this.Context.ContentResolver, documentsPath, fileName, ""); //(this.Context.ContentResolver, image, imgName.ToString(), null);
uri = Android.Net.Uri.Parse(tmpFile.Path);
// The FileOutputStream to the temporary file
var fOutStream = new FileOutputStream(tmpFile);
try
{
fOutStream.Write(thumbnail, 0, thumbnail.Length);
fOutStream.Flush();
fOutStream.Close();
DialogService.HideLoading();
DialogService.ShowSuccess("Saved picture at: " + uri.ToString());
}
catch (Java.IO.FileNotFoundException ex)
{
DialogService.ShowError(ex.InnerException.Message);
}
catch (Java.IO.IOException ex)
{
DialogService.ShowError(ex.InnerException.Message);
}
camera.StartPreview();
await App.Current.MainPage.Navigation.PushModalAsync(new InfoPage(imageBytes, tmpFile.AbsolutePath), false);
}
InfoPages view model:
ImageSource Source {get;set;}
public InfoViewModel(byte[] image, string imageUri)
{
if (image != null)
{
_image = image;
imageurl = new Uri("file:///" + imageUri, UriKind.Absolute);
Source = ImageSource.FromUri(imageurl);
}
}
All help is appreciated :)
Related
I have an mp3 file and I want to add the album art to it. The art has been saved into a temp folder, I have check this and it is there and is a jpeg.
This is the code I gave:
public void AddMp3Tags()
{
TagLib.File file = TagLib.File.Create(OutputPath + OutputName + "." + Format);
SetAlbumArt(Art, file);
file.Tag.Title = SongTitle;
file.Tag.Performers = Artists.Split(',');
file.Tag.Album = Album;
file.Tag.Track = (uint)TrackNumber;
file.Tag.Year = (uint)Convert.ToInt32(Regex.Match(Year, #"(\d)(\d)(\d)(\d)").Value);
file.Save();
}
public void SetAlbumArt(string url, TagLib.File file)
{
string path = string.Format(#"{0}temp\{1}.jpg", OutputPath, Guid.NewGuid().ToString());
using (WebClient client = new WebClient())
{
client.DownloadFile(new Uri(url), path);
}
TagLib.Picture pic = new TagLib.Picture
{
Type = TagLib.PictureType.FrontCover,
Description = "Cover",
MimeType = System.Net.Mime.MediaTypeNames.Image.Jpeg
};
MemoryStream ms = new MemoryStream();
Image image = Image.FromFile(path);
image.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
ms.Position = 0;
pic.Data = TagLib.ByteVector.FromStream(ms);
file.Tag.Pictures = new TagLib.IPicture[] { pic };
file.Save();
ms.Close();
}
All of the tags are set correctly except the art work which just shows a black box:
Black box cover art in windows media player.
I have tried many things, what am I doing wrong?
So I did some more research and it turns out that by default WMP tries to use a web service to get album artwork, I opened the song in VLC and the artwork was shown. The album code was correctly written as shown here: Mp3Tag Viewer/Editor
Another thing that I found out is that my tags were using Id3v2.4 and Id3v1. WMP does not like this for some reason so I forced TagLib to use Id3v2.3. I also changed the text encoding to UFT16 because UFT8 wasn't working. The album art is now showing in WMP and windows explorer.
I also found a way not to write the image to the disk by downloading the data from the web page and saving it to memory.
This was my final code:
public void AddMp3Tags()
{
TagLib.Id3v2.Tag.DefaultVersion = 3;
TagLib.Id3v2.Tag.ForceDefaultVersion = true;
TagLib.File file = TagLib.File.Create(OutputPath + OutputName + ".mp3");
SetAlbumArt(Art, file);
file.Tag.Title = SongTitle;
file.Tag.Performers = Artists.Split(',');
file.Tag.Album = Album;
file.Tag.Track = (uint)TrackNumber;
file.Tag.Year = (uint)Convert.ToInt32(Regex.Match(Year, #"(\d)(\d)(\d)(\d)").Value);
file.RemoveTags(file.TagTypes & ~file.TagTypesOnDisk);
file.Save();
}
public void SetAlbumArt(string url, TagLib.File file)
{
string path = string.Format(#"{0}temp\{1}.jpg", OutputPath, Guid.NewGuid().ToString());
byte[] imageBytes;
using (WebClient client = new WebClient())
{
imageBytes = client.DownloadData(url);
}
TagLib.Id3v2.AttachedPictureFrame cover = new TagLib.Id3v2.AttachedPictureFrame
{
Type = TagLib.PictureType.FrontCover,
Description = "Cover",
MimeType = System.Net.Mime.MediaTypeNames.Image.Jpeg,
Data = imageBytes,
TextEncoding = TagLib.StringType.UTF16
};
file.Tag.Pictures = new TagLib.IPicture[] { cover };
}
I hope this helps anyone that has the same problem as me and doesn't need to spend as much time figuring this out as I did.
Make sure your file downloaded successfully and try this:
public void SetAlbumArt(string url, TagLib.File file)
{
string path = string.Format(#"{0}temp\{1}.jpg", OutputPath, Guid.NewGuid().ToString());
using (WebClient client = new WebClient())
{
client.DownloadFile(new Uri(url), path);
}
file.Tag.Pictures = new TagLib.IPicture[]
{
new TagLib.Picture(new TagLib.ByteVector((byte[])new System.Drawing.ImageConverter().ConvertTo(System.Drawing.Image.FromFile(path), typeof(byte[]))))
{
Type = TagLib.PictureType.FrontCover,
Description = "Cover",
MimeType = System.Net.Mime.MediaTypeNames.Image.Jpeg
}
};
file.Save();
}
Hello i have done api for image upload on amzon s3 server with web api c#.but i want to before upload image need this image to compress but how can do that i don't know.
This is my api =>
[HttpPost]
[Route("FileUpload")]
public HttpResponseMessage FileUpload()
{
try
{
var httpRequest = HttpContext.Current.Request;
if (httpRequest.Files.Count > 0)
{
foreach (string file in httpRequest.Files)
{
var postedFile = httpRequest.Files[file];
string fname = System.IO.Path.GetFileNameWithoutExtension(postedFile.FileName.ToString());
string extension = Path.GetExtension(postedFile.FileName);
Image img = null;
string newFileName = "";
string path = "";
img = Image.FromStream(postedFile.InputStream);
string path = ConfigurationManager.AppSettings["ImageUploadPath"].ToString();
newFileName = DateTime.Now.ToString("yyyyMMddhhmmssfff") + ".jpeg";
string filePath = Path.Combine(path, newFileName);
SaveJpg(img, filePath); // here i have call method for the save image in my local system.
var client = new AmazonS3Client(Amazon.RegionEndpoint.USEast1);
try
{
PutObjectRequest putRequest = new PutObjectRequest
{
BucketName = "abc",
InputStream = postedFile.InputStream, // i need this image compress but how can do
Key = path + newFileName
};
PutObjectResponse response = client.PutObject(putRequest);
}
catch (AmazonS3Exception amazonS3Exception)
{
if (amazonS3Exception.ErrorCode != null &&
(amazonS3Exception.ErrorCode.Equals("InvalidAccessKeyId")
||
amazonS3Exception.ErrorCode.Equals("InvalidSecurity")))
{
throw new Exception("Check the provided AWS Credentials.");
}
else
{
throw new Exception("Error occurred: " + amazonS3Exception.Message);
}
}
return Request.CreateResponse(HttpStatusCode.OK, Status);
}
}
}
catch (Exception ex)
{
}
return Request.CreateResponse(HttpStatusCode.OK, "Done");
}
This is my ImageCompress method =>
public static void SaveJpg(Image image, string file_name, long compression = 60)
{
try
{
EncoderParameters encoder_params = new EncoderParameters(1);
encoder_params.Param[0] = new EncoderParameter(
System.Drawing.Imaging.Encoder.Quality, compression);
ImageCodecInfo image_codec_info =
GetEncoderInfo("image/jpeg");
image.Save(file_name, image_codec_info, encoder_params);
}
catch (Exception ex)
{
}
}
This is my api and i need this image to before upload image compress and then after i want to upload this image so any one idea how can do that please let me know.
I'm developing an mobile application using Xamarin Forms where in an app send an image to server. For sending image we've used WCF services.
Well below is the code for Xamarin Application
using (var memoryStream = new MemoryStream())
{
pick.GetStream().CopyTo(memoryStream);
pick.Dispose();
byte[] byteImageArray = memoryStream.ToArray();
try
{
var imageStream = new ByteArrayContent(byteImageArray);
var multi = new MultipartContent();
multi.Add(imageStream);
var client = new HttpClient();
var result = client.PostAsync("http://www.test.com/Services/Service.svc/SaveImage", multi).Result;
var json = await result.Content.ReadAsStringAsync();
var strNo = JsonConvert.DeserializeObject<string>(json);
}
catch (Exception ex)
{
await DisplayAlert("Error", ex.Message, "Ok");
}
}
And for WCF services
public string SaveImage(Stream data)
{
byte[] byteImage = ReadFully(data);
//Database logic to insert byte array
}
public static byte[] ReadFully(Stream input)
{
using (MemoryStream ms = new MemoryStream())
{
input.CopyTo(ms);
return ms.ToArray();
}
}
Now with this code image is getting converted successfully and getting stored in database blob.
Issue I'm facing is whenever I convert blob back to image, the image gets corrupted. When I insert image into blob with asp.net application the data length of blob is displayed as 18901 whereas while inserting same image with mobile application data length is 18987.
Please help me to resolve the data length issue, or please guide easier way to store image into data base using WCF and Xamarin forms.
Create an WebAPI called PicturesController for example. You must use PUT verb
/// <summary>
/// Receiving an image across WebAPI
/// </summary>
/// <returns></returns>
[HttpPut]
public HttpResponseMessage Put()
{
var result = new HttpResponseMessage(HttpStatusCode.OK);
if (Request.Content.IsMimeMultipartContent())
{
try
{
Request.Content.LoadIntoBufferAsync().Wait();
Request.Content.ReadAsMultipartAsync<MultipartMemoryStreamProvider>(
new MultipartMemoryStreamProvider()).ContinueWith((task) => {
MultipartMemoryStreamProvider provider = task.Result;
foreach (HttpContent content in provider.Contents)
{
Stream stream = content.ReadAsStreamAsync().Result;
Image image = Image.FromStream(stream);
try
{
string filename = string.Format("{0}{1}{2}{3}",
DateTime.Now.Year,
DateTime.Now.Month,
DateTime.Now.Day,
DateTime.Now.Second) + ".jpg";
foreach (var h in content.Headers.ContentDisposition.Parameters)
{
if (h.Name.ToLower() == "filename")
{
filename = h.Value.Replace("\\", "/").Replace("\"", "");
var pos = filename.LastIndexOf("/");
if (pos >= 0)
{
filename = filename.Substring(pos + 1);
}
break;
}
}
string filePath = ConfigurationManager.AppSettings["Pictures"]
.ToString();
string fullPath = Path.Combine(filePath, filename);
EncoderParameters encparams = new EncoderParameters(1);
encparams.Param[0] = new EncoderParameter(Encoder.Quality, 80L);
ImageCodecInfo ici = null;
foreach (ImageCodecInfo codec in ImageCodecInfo
.GetImageEncoders())
{
if (codec.MimeType == "image/jpeg")
{
ici = codec;
break;
}
}
image.JpegOrientation().Save(fullPath, ici, encparams);
}
catch (Exception ex)
{
}
}
});
}
catch (Exception ex)
{
result.StatusCode = HttpStatusCode.InternalServerError;
}
return result;
}
else
{
throw new HttpResponseException(Request.CreateResponse(
HttpStatusCode.NotAcceptable,
"This request is not properly formatted"));
}
}
In this code I create a temporary file name. If you pass one as header parameter, I use that. I save the image in a folder Pictures and I read this folder from web.config. The file is in jpeg format because usually this is the image format on your device.
When you do that, you have to create a webclient in your Xamarin project.
/// <summary>
/// Uploads the photo.
/// </summary>
/// <returns>The photo.</returns>
/// <param name="photoBytes">Photo bytes.</param>
public async Task<bool> UploadPhoto(byte[] photoBytes, int PropertyId, string fileName)
{
bool rtn = false;
var content = new MultipartFormDataContent();
var fileContent = new ByteArrayContent(photoBytes);
fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data");
fileContent.Headers.ContentDisposition =
new ContentDispositionHeaderValue("attachment") {
FileName = fileName + ".jpg"
};
content.Add(fileContent);
fileContent.Headers.ContentDisposition.Parameters.Add(
new NameValueHeaderValue("<otherParam>", "<otherParamValue>"));
string url = RestURL() + "Pictures/Put";
try
{
using (var client = new HttpClient())
{
// add an authotization token if you have one
//client.DefaultRequestHeaders.Add("authenticationToken", "yourToken");
await client.PutAsync(url, content);
rtn = true;
}
}
catch (Exception ex)
{
}
return rtn;
}
Remember to include
using System.Net.Http;
using System.Net.Http.Headers;
I'm using this implementation in a lot of apps and it's working perfectly. If you have any suggestion to improve it, tell me please.
Simply changing
var multi = new MultipartContent();
multi.Add(imageStream);
To
StreamContent scontent = new StreamContent(pick.GetStream());
HttpContent hp = scontent;
Resolved the issue. Hope I'm not going wrong anywhere.
I'm using Xamarin for Android. I load an image and put it in ImageView, then I edit the image. Next I want to save that image to SD card.
Anyone know how to save the image into SD card because I only can find it in Java Android. I already try to convert the code from Java to C# but still get an error.
Any help, thanks in advance.
I get an error at InputStream iS = Resources.OpenRawResource(Resource.Drawable.Icon); as the error is "cannot implicitly convert type 'System.IO.Stream' to 'Java.IO.InputStream'"
Here's the code:
Java.IO.File path = Android.OS.Environment.GetExternalStoragePublicDirectory (Android.OS.Environment.DirectoryPictures);
Java.IO.File file = new Java.IO.File (path, "Icon.png");
try {
path.Mkdirs();
InputStream iS = Resources.OpenRawResource(Resource.Drawable.Icon);
OutputStream oS = new FileOutputStream(file);
byte[] data = new byte[iS.Available()];
iS.Read(data);
oS.Write(data);
iS.Close();
oS.Close();
} catch (Exception ex) {
// ...
}
I use this to save the captured photo to sdcard:
public void OnPictureTaken(byte[] data, Android.Hardware.Camera camera)
{
// Save the image JPEG data to the SD card
FileOutputStream outStream = null;
File dataDir = Android.OS.Environment.ExternalStorageDirectory;
if (data!=null)
{
try
{
outStream = new FileOutputStream(dataDir + "/" + PICTURE_FILENAME);
outStream.Write(data);
outStream.Close();
}
catch (FileNotFoundException e)
{
Android.Util.Log.Debug("SIMPLECAMERA", e.Message);
}
catch (IOException e)
{
Android.Util.Log.Debug("SIMPLECAMERA", e.Message);
}
File file = new File(dataDir + "/" + PICTURE_FILENAME);
try
{
ExifInterface exif = new ExifInterface(file.CanonicalPath);
// Read the camera model and location attributes
exif.GetAttribute(ExifInterface.TagModel);
float[] latLng = new float[2];
exif.GetLatLong(latLng);
// Set the camera make
exif.SetAttribute(ExifInterface.TagMake, “My Phone”);
exif.SetAttribute(ExifInterface.TagDatetime,
System.DateTime.Now.ToString());
}
catch (IOException e) {
Android.Util.Log.Debug("SIMPLECAMERA", e.Message);
}
}
else
{
Toast.MakeText(this, "No Image Captured", ToastLength.Long);
}
}
found the answer, credit to Mohd Riyaz.
var yourImageView = new ImageView(this); //Your image view
var fetchedDrawable = yourImageView.Drawable;
BitmapDrawable bitmapDrawable = (BitmapDrawable)fetchedDrawable;
var bitmap = bitmapDrawable.Bitmap;
using (var stream = new FileStream("AbsolutePath_File", FileMode.Create))
{
bitmap.Compress(Bitmap.CompressFormat.Jpeg, 100, stream);
}
Following is the code to retrieve image from database and then saving it to a folder.
public string BinarytoNewsImage(int ID)
{
byte[] btimage = null;
string image = "";
string filename = null;
int mediaid;
DataSet dsNews = new DataSet();
adp = new SqlDataAdapter("Select Top 1 * from tblNew Where intNewId=" + ID, offcon);
adp.Fill(dsNews, "tblNews1");
if (dsNews.Tables["tblNews1"].Rows.Count > 0)
{
if (dsNews.Tables["tblNews1"].Rows[0]["strImage"] != DBNull.Value)
{
btimage = (byte[])dsNews.Tables["tblNews1"].Rows[0]["strImage"];
mediaid = Convert.ToInt32(dsNews.Tables["tblNews1"].Rows[0]["intMediaId"].ToString());
filename = dsNews.Tables["tblNews1"].Rows[0]["strfilename"].ToString();
image = BinarytoImage(btimage, mediaid);
}
else
{
filename = dsNews.Tables["tblNews1"].Rows[0]["strfilename"].ToString();
image = "http://www.patrika.com/media/" + filename;
}
}
return image;
}
public string BinarytoImage(byte[] stream, int ID)
{
string ImagePath = "";
string Image = ID + ".jpg";
var URL = System.Configuration.ConfigurationManager.AppSettings["ImagePath"].ToString();
string FolderName = new Uri(URL).LocalPath;
var help = HttpContext.Current.Server.MapPath(FolderName);
if (Directory.Exists(HttpContext.Current.Server.MapPath(FolderName)))
{
string[] files = Directory.GetFiles(HttpContext.Current.Server.MapPath(FolderName), ID + ".jpg");
if (files.Length > 0)
{
ImagePath = URL + ID + ".jpg";
}
else
{
using (MemoryStream MS = new MemoryStream(stream, 0, stream.Length))
{
MS.Write(stream, 0, stream.Length);
System.Drawing.Image img = System.Drawing.Image.FromStream(MS);
img.Save(help + ID + ".jpg", System.Drawing.Imaging.ImageFormat.Gif);
img.Dispose();
img = null;
ImagePath = URL + ID + ".jpg";
}
}
}
return ImagePath;
}
Everything is working fine the images are saving to a folder but my problem is images are getting blur after retrieval.
I just don't know the reason as when I am using another code for retrieval than images are coming fine but are not saved to folder:
DataSet dsNews = new DataSet();
adp = new SqlDataAdapter("Select Top 1 * from tblNew Where intNewId=901371", con);
adp.Fill(dsNews, "tblNews1");
if (dsNews.Tables["tblNews1"].Rows[0]["strImage"] != DBNull.Value)
{
byte[] btimage = (byte[])dsNews.Tables["tblNews1"].Rows[0]["strImage"];
Response.ContentType = "image/jpeg";
Response.BinaryWrite(btimage);
}
I need those images to be saved to folder so that I don't have to call database after once image comes.
Wouldn't it help to change this line
img.Save(help + ID + ".jpg", System.Drawing.Imaging.ImageFormat.Gif);
to store it as JPEG rather? as that's the source format
EDIT:
Your are not moving the stream pointer back to the start.
Try change these lines:
using (MemoryStream MS = new MemoryStream(stream, 0, stream.Length))
{
MS.Write(stream, 0, stream.Length);
System.Drawing.Image img = System.Drawing.Image.FromStream(MS);
...
To
using (MemoryStream MS = new MemoryStream(stream, 0, stream.Length))
{
MS.Write(stream, 0, stream.Length);
MS.Seek(0, SeekOrigin.Begin);
System.Drawing.Image img = System.Drawing.Image.FromStream(MS);
...
I write the common method, all is ok.
Maybe your byte[]stream is not right,pls check.
byte[] stream = File.ReadAllBytes(#"D:\YWG\123.jpg");
using (MemoryStream MS = new MemoryStream(stream, 0, stream.Length))
{
MS.Write(stream, 0, stream.Length);
using (Image img = Image.FromStream(MS))
{
img.Save(#"D:\dd.jpg", System.Drawing.Imaging.ImageFormat.Gif);
}
}
I see the dest file "dd.jpg" is ok.