When my images are being loaded from my database on my web server, I see the following error:
A generic error occurred in GDI+. at
System.Drawing.Image.Save(Stream stream, ImageCodecInfo encoder,
EncoderParameters encoderParams) at
System.Drawing.Image.Save(Stream stream, ImageFormat format) at
MyWeb.Helpers.ImageHandler.ProcessRequest(HttpContext context)
All my code is attempting to do is load the image, can anybody take a look and let me know what I'm doing wrong?
Note - This works if I test it on my local machine, but not when I deploy it to my web server.
public void ProcessRequest(HttpContext context)
{
context.Response.Clear();
if (!String.IsNullOrEmpty(context.Request.QueryString["imageid"]))
{
int imageID = Convert.ToInt32(context.Request.QueryString["imageid"]);
int isThumbnail = Convert.ToInt32(context.Request.QueryString["thumbnail"]);
// Retrieve this image from the database
Image image = GetImage(imageID);
// Make it a thumbmail if requested
if (isThumbnail == 1)
{
Image.GetThumbnailImageAbort myCallback = new Image.GetThumbnailImageAbort(ThumbnailCallback);
image = image.GetThumbnailImage(200, 200, myCallback, IntPtr.Zero);
}
context.Response.ContentType = "image/png";
// Save the image to the OutputStream
image.Save(context.Response.OutputStream, ImageFormat.Png);
}
else
{
context.Response.ContentType = "text/html";
context.Response.Write("<p>Error: Image ID is not valid - image may have been deleted from the database.</p>");
}
}
The error occurs on the line:
image.Save(context.Response.OutputStream, ImageFormat.Png);
UPDATE
I've changed my code to this, bit the issue still happens:
var db = new MyWebEntities();
var screenshotData = (from screenshots in db.screenshots
where screenshots.id == imageID
select new ImageModel
{
ID = screenshots.id,
Language = screenshots.language,
ScreenshotByte = screenshots.screen_shot,
ProjectID = screenshots.projects_ID
});
foreach (ImageModel info in screenshotData)
{
using (MemoryStream ms = new MemoryStream(info.ScreenshotByte))
{
Image image = Image.FromStream(ms);
// Make it a thumbmail if requested
if (isThumbnail == 1)
{
Image.GetThumbnailImageAbort myCallback = new Image.GetThumbnailImageAbort(ThumbnailCallback);
image = image.GetThumbnailImage(200, 200, myCallback, IntPtr.Zero);
}
context.Response.ContentType = "image/png";
// Save the image to the OutputStream
image.Save(context.Response.OutputStream, ImageFormat.Png);
} }
Thanks.
Probably for the same reason that this guy was having problems - because the for a lifetime of an Image constructed from a Stream, the stream must not be destroyed.
So if your GetImage function constructs the returned image from a stream (e.g. a MemoryStream) and then closes the stream before returning the image then the above will fail. My guess is that your GetImage looks a tad like this:
Image GetImage(int id)
{
byte[] data = // Get data from database
using (MemoryStream stream = new MemoryStream(data))
{
return Image.FromStream(data);
}
}
If this is the case then try having GetImage return the MemoryStream (or possibly the byte array) directrly so that you can create the Image instance in your ProcessRequest method and dispose of the stream only when the processing of that image has completed.
This is mentioned in the documentation but its kind of in the small print.
Related
I hope you're having some advice because I'm pretty much out of options. What I'm trying to do:
upload an image to a blobcontainer via the azure portal
when doing that, the blobtrigger below fires.
I want to resize the incoming image which is a Microsoft.Azure.WebJobs.Host.Blobs.WatchableReadStream object.
I want to upload the result to a new blob container.
The issue is, when I am passing any other Stream, e.g. a MemoryStream than the unmodified myBlob object the UploadAsync method seems to silently fail and the BlobTrigger fires again, starting an endless loop. Writing to the current myBlob object also silently fails. Only thing which works is passing the myBlob object in BlockBlobClient.UploadAsync without ANY modification whatsoever, which is useless. I am doing a remote debugging session in Azure.
Also, when I try to feed a MemoryStream object to the UploadAsync method the same problem occurs. The method below is the blob trigger:
public async Task UploadImage([BlobTrigger("mediafullsizecontainer/{name}", Connection = "AzureWebJobsStorage")]Stream myBlob, string name, ILogger log)
{
BlockBlobClient fullsizeBlobClient = _mediaFullsizeContainerClient.GetBlockBlobClient(name);
Response<BlobProperties> blobPropertiesResponse = await fullsizeBlobClient.GetPropertiesAsync(null, default);
BlobProperties blobProperties = blobPropertiesResponse.Value;
//Only process blobs when the correct metadata properties are set
if (blobProperties.Metadata.Any(property => property.Key == "category" & property.Value != String.Empty))
{
string category = blobProperties.Metadata["category"];
Stream s = await ResizeImage(myBlob);
BlockBlobClient thumbnailBlobclient = _mediaThumbnailContainerClient.GetBlockBlobClient(name);
Response<BlobContentInfo> uploadResponse = await thumbnailBlobclient.UploadAsync(s, new BlobUploadOptions(), default);
BlobContentInfo blobContentInfo = uploadResponse.Value;
}
}
The ResizeImage method uses the SixLabors.ImageSharp image processing library.
public async Task<Stream> ResizeImage(Stream inputStream)
{
(Image image, IImageFormat imageFormat) imageWithFormat = await Image.LoadWithFormatAsync(inputStream);
int height = imageWithFormat.image.Height;
int width = imageWithFormat.image.Width;
imageWithFormat.image.Mutate(operation => {
operation.Resize(width / 4, height / 4);
});
MemoryStream outputStream = new MemoryStream();
imageWithFormat.image.Save(outputStream, imageWithFormat.imageFormat);
return outputStream;
}
So when I do a mock change on the myBlob object like this, myBlob.Write(buffer) fails:
byte[] buffer = new byte[myBlob.Length];
myBlob.Read(buffer, 0, (int)myBlob.Length);
myBlob.Position = 0;
myBlob.Write(buffer);
When I copy the myBlob contents to a MemoryStream and pass the memoryStream to UploadAsync, UploadAsync fails:
MemoryStream ms = new MemoryStream();
myBlob.CopyTo(ms);
BlockBlobClient thumbnailBlobclient = _mediaThumbnailContainerClient.GetBlockBlobClient(name);
Response<BlobContentInfo> uploadResponse = await thumbnailBlobclient.UploadAsync(ms, new BlobUploadOptions(), default);
Only thing which works is passing the myBlob object without any modification to UploadAsync which is useless since I need to modify the incoming stream:
public async Task UploadImage([BlobTrigger("mediafullsizecontainer/{name}", Connection = "AzureWebJobsStorage")]Stream myBlob, string name, ILogger log)
{
BlockBlobClient fullsizeBlobClient = _mediaFullsizeContainerClient.GetBlockBlobClient(name);
Response<BlobProperties> blobPropertiesResponse = await fullsizeBlobClient.GetPropertiesAsync(null, default);
BlobProperties blobProperties = blobPropertiesResponse.Value;
//Only process blobs when the correct metadata properties are set
if (blobProperties.Metadata.Any(property => property.Key == "category" & property.Value != String.Empty))
{
string category = blobProperties.Metadata["category"];
BlockBlobClient thumbnailBlobclient = _mediaThumbnailContainerClient.GetBlockBlobClient(name);
Response<BlobContentInfo> uploadResponse = await thumbnailBlobclient.UploadAsync(myBlob, new BlobUploadOptions(), default);
BlobContentInfo blobContentInfo = uploadResponse.Value;
}
}
How can I pass a custom stream to the UploadAsync method? The documentation on https://learn.microsoft.com/en-us/dotnet/api/azure.storage.blobs.specialized.blockblobclient.uploadasync?view=azure-dotnet says you just need a stream object - but this does not work. Thanks in advance.
Ok looks like I found the answer myself, I got rid of the dreaded UploadAsync method and did it like this by reading the outputStream of the resized image into a buffer then opening a Stream for writing to the thumbnailBlobclient object and passing the buffer to the stream object. It makes sense that trying to modify the incoming myBlob object which came with the trigger, fires the trigger again and creating a loop.
Stream outputStream = await ResizeAndCropImage(myBlob);
byte[] buffer = new byte[outputStream.Length];
outputStream.Read(buffer);
BlockBlobClient thumbnailBlobclient = _mediaThumbnailContainerClient.GetBlockBlobClient(name);
Stream s = thumbnailBlobclient.OpenWrite(true, new BlockBlobOpenWriteOptions { HttpHeaders = new BlobHttpHeaders { ContentType = "image/jpg" } }, default); //set http headers here as well?
await s.WriteAsync(buffer);
s.Close();
I will set the content type in a more generic way but this concept is working.
Can someone tell me why I keep getting a read and write timeout on this function? I have this as a code behind function on click even from a button. Everything as far as the data looks good until I get to the stream section and it still steps through, but when I check the Stream object contents after stepping into that object it states Read Timeout/Write Timeout: System invalid Operation Exception.
protected void SubmitToDB_Click(object sender, EventArgs e)
{
if (FileUploader.HasFile)
{
try
{
if (SectionDropDownList.SelectedValue != null)
{
if (TemplateDropDownList.SelectedValue != null)
{
// This gets the full file path on the client's machine ie: c:\test\myfile.txt
string strFilePath = FileUploader.PostedFile.FileName;
//use the System.IO Path.GetFileName method to get specifics about the file without needing to parse the path as a string
string strFileName = Path.GetFileName(strFilePath);
Int32 intFileSize = FileUploader.PostedFile.ContentLength;
string strContentType = FileUploader.PostedFile.ContentType;
//Convert the uploaded file to a byte stream to save to your database. This could be a database table field of type Image in SQL Server
Stream strmStream = FileUploader.PostedFile.InputStream;
Int32 intFileLength = (Int32)strmStream.Length;
byte[] bytUpfile = new byte[intFileLength + 1];
strmStream.Read(bytUpfile, 0, intFileLength);
strmStream.Close();
saveFileToDb(strFileName, intFileSize, strContentType, bytUpfile); // or use FileUploader.SaveAs(Server.MapPath(".") + "filename") to save to the server's filesystem.
lblUploadResult.Text = "Upload Success. File was uploaded and saved to the database.";
}
}
}
catch (Exception err)
{
lblUploadResult.Text = "The file was not updloaded because the following error happened: " + err.ToString();
}
}
else
{
lblUploadResult.Text = "No File Uploaded because none was selected.";
}
}
Try something like this:
using (var fileStream = FileUploader.PostedFile.InputStream)
{
using (var reader = new BinaryReader(fileStream))
{
byte[] bytUpfile = reader.ReadBytes((Int32)fileStream.Length);
// SAVE TO DB...
}
}
I'm new to Xamarin. I'm trying display a list of downloaded images. I am downloading images from an APP API on Azure, where I stored the file on Azure Storage.
My server code is the following:
public HttpResponseMessage Get(string PK, string RK)
{
//Creating CloudBlockBlolb...
byte[] bytes = new byte[blockBlob.Properties.Length]
for(int i = 0; i < blockBlob.Properties.Length; i++){
bytes[i] = 0x20;
}
blockBlob.DownloadToByteArray(bytes, 0);
HttpResponseMessage resp = new HttpResponseMessage(HttpStatusCode.OK);
resp.Content = new ByteArrayContent(bytes);
resp.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("image/jpg");
return resp;
}
My Xamarin code is the following:
public MainPage ()
{
//...
List<PicturePost> list = new List<PicturePost>{
new PicturePost("title", "subtitle", "link/api/Pictures?PK=xxx&RK=yyy")
};
InitializeComponent ();
listView.ItemTemplate = new DataTemplate (typeof(CustomImageCell));
listView.HasUnevenRows = true;
listView.ItemsSource = list;
//...
}
And here is the relevant code for CustomImageCell:
var image = new Image ();
image.SetBinding (Image.SourceProperty, "image");
//...
horizontalLayout.Children.Add (image);
I know that my API call works, because when I test it on the browser, it returns the image. I also know that if I use any random links such as http://www.natureasia.com/common/img/splash/thailand.jpg the image is downloaded and displayed properly. It is only when I use the API link that it doesn't seem to be working. Can someone tell me what I am doing wrong?
so in my public MainPage(), I added the following:
listView.BeginRefresh ();
listView.EndRefresh ();
I realized at some point that the images would take some time to download. I assume that when the listView was created, the images were not finished downloading, so I added the code above... Pretty sure this is not the best way to do this (probably an await would be better, but I don't know where).
I have very uncommon problem. firstly let me tell you that i want to build a WP8 apps about images. I have some images stored in the project solution and using those for the apps and it is working fine.
i am using one
public Stream ImageStream
{
get
{
return this.imageStream;
}
set
{
this.imageStream = value;
}
}
Now for the project solution images this Image stream i am calling like this
StreamResourceInfo imageRes = Application.GetResourceStream(new Uri("WindowsPhone;component/Images/Image1.jpg", UriKind.Relative));
this.ImageStream = imageRes.Stream;
Now the problem begins if I try to use any image from media library. I can store the file into Isolated storage and from their I can access the file. What I am doing is
using (IsolatedStorageFile Iso = IsolatedStorageFile.GetUserStoreForApplication())
{
using (var stream = new IsolatedStorageFileStream(strFileName, FileMode.Open, FileAccess.Read, Iso))
{
IsolatedStorageFileStream fileStream = Iso.OpenFile(strFileName, FileMode.Open, FileAccess.Read);
data = new byte[stream.Length];
// Read the entire file and then close it
stream.Read(data, 0, data.Length);
stream.Close();
}
}
MemoryStream ms = new MemoryStream(data);
BitmapImage bi = new BitmapImage();
// Set bitmap source to memory stream
bi.SetSource(ms);
However i can use the image file and can show but you can see it is a bit map image, and as it is in isolated storage I can not use
StreamResourceInfo imageRes ...
this.ImageStream = ...
Any help how can I use this.ImageSteam Properties? any other ideas will be welcome. I am actually beginner in WP8 programming
Or Let me ask you a simple Question how can I read a image which is in isolatedstorage to StreamResourceInfo ?
If I can do that my problem is solved. please help me.
*Save Image to Isolated Storage: *
String tempJPEG = "logo.jpg";
// Create virtual store and file stream. Check for duplicate tempJPEG files.
using (IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
if (myIsolatedStorage.FileExists(tempJPEG))
{
myIsolatedStorage.DeleteFile(tempJPEG);
}
IsolatedStorageFileStream fileStream = myIsolatedStorage.CreateFile(tempJPEG);
StreamResourceInfo sri = null;
Uri uri = new Uri(tempJPEG, UriKind.Relative);
sri = Application.GetResourceStream(uri);
BitmapImage bitmap = new BitmapImage();
bitmap.SetSource(sri.Stream);
WriteableBitmap wb = new WriteableBitmap(bitmap);
// Encode WriteableBitmap object to a JPEG stream.
Extensions.SaveJpeg(wb, fileStream, wb.PixelWidth, wb.PixelHeight, 0, 85);
//wb.SaveJpeg(fileStream, wb.PixelWidth, wb.PixelHeight, 0, 85);
fileStream.Close();
}
Happy Coding...
why execute a stream copy ?
http://www.windowsphonegeek.com/tips/All-about-WP7-Isolated-Storage---Read-and-Save-Images
try something like
BitmapImage bi = new BitmapImage();
using (IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream fileStream = myIsolatedStorage.OpenFile("logo.jpg", FileMode.Open, FileAccess.Read))
{
bi.SetSource(fileStream);
this.img.Height = bi.PixelHeight;
this.img.Width = bi.PixelWidth;
}
}
this.img.Source = bi;
I'm trying to get a thumbnail image for a video that I've just chosen (or recorded) via the UIImagePickerController. In my picker's FinishedPickingMedia method, I get what I believe to be the path to the video file and use it to save the recording to album. The newly recorded video does indeed appear in my album. Now to get the thumbnail…
I've tried using the ALAssetsLibrary in a couple ways. First, I've enumerated all the videos and tried to find a match from the asset's UtiToUrlDictionary.Values[0] value, which reveals its file path. No entries matched the path I obtained from the FinishedPickingMedia method's mediaUrlKey.
My second attempt was to use the ALAssetsLibrary's AssetForUrl() method. Again, I tried my FinishedPickingMedia method's mediaUrlKey, but there was no match.
The UIImagePickerController -> FinishedPickingMedia -> mediaUrlKey returns a path of:
file://localhost/private/var/mobile/Applications/73037738-C060-4DE6-A1CA-698E6BE083F2/tmp//trim.iRBwWw.MOV
After painful digging and inspecting every video in my library, it the same video's path from the ALAssetsLibrary is:
assets-library://asset/asset.MOV?id=B073FCF6-83ED-436B-AFD8-42D0A6C70FC6&ext=MOV
Why are the video paths different between UIIMagePickerController and ALAssetsLibrary? How can I get ALAssetsLibrary to return the same video picked from UIImagePickerController?
[code for the picker]
public override void FinishedPickingMedia (UIImagePickerController picker, NSDictionary info)
{
var mediaUrlKey = new NSString("UIImagePickerControllerMediaURL");
var mediaPath = (NSUrl) info.ObjectForKey(mediaUrlKey);
if( recordView.RecordVideo )
{
if(mediaPath != null)
{
if(UIVideo.IsCompatibleWithSavedPhotosAlbum(mediaPath.Path))
{
UIVideo.SaveToPhotosAlbum(mediaPath.Path, SaveToPhotosAlbumResults);
}
else
{
using (var alert = new UIAlertView("Problem Encountered",
"Unable to save this recording.", null, "Ok!", null))
{
alert.Show();
}
}
}
}
else
{
recordView.VideoFileLocation = mediaPath;
//ALAssetsLibrary library = new ALAssetsLibrary();
//library.AssetForUrl( mediaPath, GetAssetResult, GetAssetError );
}
recordView.VideoFileLocation = mediaPath;
Console.WriteLine("***" + recordView.VideoFileLocation.ToString()+ "***");
recordView.ShowUploadButton();
recordView.SetThumbnailImage();
picker.DismissModalViewControllerAnimated(true);
}
Thank you
I think may be it is too late but the following code work as of now
public static UIImage GenerateImage(NSUrl videoUrl)
{
var asset = AVAsset.FromUrl(videoUrl);
var imageGenerator = AVAssetImageGenerator.FromAsset(asset);
imageGenerator.AppliesPreferredTrackTransform = true;
var actualTime = asset.Duration;
CoreMedia.CMTime cmTime = new CoreMedia.CMTime(1, 60);
NSError error;
var imageRef = imageGenerator.CopyCGImageAtTime(cmTime, out actualTime, out error);
if (imageRef == null)
return null;
var image = UIImage.FromImage(imageRef);
return image;
}
I think the section Can I Get To The Original File Representing This Image on the Disk in this question can help you.
This is how you can get a thumbnail within the picker delegate:
NSUrl data = new NSUrl(info.ObjectForKey(new NSString("UIImagePickerControllerMediaURL")).ToString());
//get the video thumbnail
MPMoviePlayerController movie = new MPMoviePlayerController(data);
movie.Stop();
UIImage videoThumbnail = movie.ThumbnailImageAt(0.0,MPMovieTimeOption.NearestKeyFrame);
movie.Stop();