How to save an image in SQLite in Xamarin Forms? - sqlite

I have the following two methods that handles taking photos from a camera and picking photos from a library. They're both similar methods as at the end of each method, I get an ImageSource back from the Stream and I pass it onto another page which has an ImageSource binding ready to be set. These two method work perfectly. The next step now is to save the Image in SQLite so I can show the images in a ListView later on. My question for the XamGods (Xamarin Pros =), what is the best way to save image in SQLite in 2019? I have been in the forums for hours and I still don't have a tunnel vision on what I want to do. I can either
Convert Stream into an array of bytes to save in Sqlite.
Convert ImageSource into an array of bytes (messy/buggy).
Somehow retrieve the actual Image selected/taken and convert that into an array of bytes into SQLite
I'm sorry if my question is general, but Xamarin does not provide a clear-cut solution on how to save images in SQLite and you can only find bits and pieces of solutions throughout the forums listed below.
How to save and retrieve Image from Sqlite
Load Image from byte[] array.
Creating a byte array from a stream
Thank you in advance!
private async Task OnAddPhotoFromCameraSelected()
{
Console.WriteLine("OnAddPhotoFromCameraSelected");
var photo = await Plugin.Media.CrossMedia.Current.TakePhotoAsync(new Plugin.Media.Abstractions.StoreCameraMediaOptions() { });
var stream = photo.GetStream();
photo.Dispose();
if (stream != null)
{
ImageSource cameraPhotoImage = ImageSource.FromStream(() => stream);
var parms = new NavigationParameters();
parms.Add("image", cameraPhotoImage);
var result = await NavigationService.NavigateAsync("/AddInspectionPhotoPage?", parameters: parms);
if (!result.Success)
{
throw result.Exception;
}
}
}
private async Task OnAddPhotoFromLibrarySelected()
{
Console.WriteLine("OnAddPhotoFromLibrarySelected");
Stream stream = await DependencyService.Get<IPhotoPickerService>().GetImageStreamAsync();
if (stream != null)
{
ImageSource selectedImage = ImageSource.FromStream(() => stream);
var parms = new NavigationParameters();
parms.Add("image", selectedImage);
parms.Add("stream", stream);
var result = await NavigationService.NavigateAsync("/AddInspectionPhotoPage?", parameters: parms);
if (!result.Success)
{
throw result.Exception;
}
}
}

As Jason said that you can save image path into sqlite database, but if you still want to save byte[] into sqlite database, you need to convert stream into byte[] firstly:
private byte[] GetImageBytes(Stream stream)
{
byte[] ImageBytes;
using (var memoryStream = new System.IO.MemoryStream())
{
stream.CopyTo(memoryStream);
ImageBytes = memoryStream.ToArray();
}
return ImageBytes;
}
Then load byte[] from sqlite, converting into stream.
public Stream BytesToStream(byte[] bytes)
{
Stream stream = new MemoryStream(bytes);
return stream;
}
For simple sample, you can take a look:
Insert byte[] in sqlite:
private void insertdata()
{
var path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "sqlite1.db3");
using (var con = new SQLiteConnection(path))
{
Image image = new Image();
image.Content = ConvertStreamtoByte();
var result = con.Insert(image);
sl.Children.Add(new Label() { Text = result > 0 ? "insert successful insert" : "fail insert" });
}
}
Loading image from sqlite:
private void getdata()
{
var path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "sqlite1.db3");
using (var con = new SQLiteConnection(path))
{
var image= con.Query<Image>("SELECT content FROM Image ;").FirstOrDefault();
if(image!=null)
{
byte[] b = image.Content;
Stream ms = new MemoryStream(b);
image1.Source = ImageSource.FromStream(() => ms);
}
}
}
Model:
public class Image
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public string FileName { get; set; }
public byte[] Content { get; set; }
}

Related

Issue with loading dicom images in WADO loader

I am working on a web based OHIF Dicom viewer. I am using clear canvas as my PACs server. So I developed one broker application in .net core which works like WADO-RS and supply information to OHIF viewer from clear canvas. In my broker application I am passing metadata to OHIF viewer in json format by using FO-dicom json converter which converts dcm file into Json string.
My code for sending metadata:
var files = Directory.GetFiles(directory);
List<JObject> lstjo = new List<JObject>();
JObject jo;
foreach (var file in files)
{
var dicomDirectory = DicomFile.Open(file, FileReadOption.ReadAll);
if (dicomDirectory.Dataset.InternalTransferSyntax.UID.UID != DicomTransferSyntax.ImplicitVRLittleEndian.UID.UID)
{
var transcoder = new DicomTranscoder(dicomDirectory.Dataset.InternalTransferSyntax, DicomTransferSyntax.ImplicitVRLittleEndian);
dicomDirectory = transcoder.Transcode(dicomDirectory);
}
JsonDicomConverter dicomConverter = new JsonDicomConverter();
StringBuilder sb = new StringBuilder();
StringWriter sw = new StringWriter(sb);
JsonWriter writer = new JsonTextWriter(sw);
Newtonsoft.Json.JsonSerializer serializer = new Newtonsoft.Json.JsonSerializer();
dicomConverter.WriteJson(writer, dicomDirectory.Dataset, serializer);
jo = JObject.Parse(sb.ToString());
// jo.Property("7FE00010").Remove();
retJsonstring += jo.ToString() + ",";
}
if (retJsonstring.Length > 6)
{
retJsonstring = retJsonstring.Substring(0, retJsonstring.Length - 1) + "]";
}
else
{
retJsonstring += "]";
}
retJsonstring = retJsonstring.Replace("\r", "").Replace("\n", "");
}
return retJsonstring;
During passing metadata there is no issue in Ohif viewer. After then OHIF viewer sending WADORS request for frames to display. My broker application also send responding for that request in multipart.
My code for sending Multipart response :
{
var dicomFile = DicomFile.Open(path, FileReadOption.ReadAll);
string transfersyntax = dicomFile.Dataset.InternalTransferSyntax.UID.UID;
MemoryStream streamContent = new MemoryStream();
if (transfersyntax != DicomTransferSyntax.ImplicitVRLittleEndian.UID.UID)
{
var transcoder = new DicomTranscoder(dicomFile.Dataset.InternalTransferSyntax, DicomTransferSyntax.ImplicitVRLittleEndian);
dicomFile = transcoder.Transcode(dicomFile);
}
dicomFile.Save(streamContent);
DicomImage img = new DicomImage(dicomFile.Dataset, 0);
streamContent.Seek(0, SeekOrigin.Begin);
string boundary = Guid.NewGuid().ToString();
MultipartContent multipartContent = new MultipartContent();
//newFile.Save(multipartContent.Stream);
multipartContent.Stream = streamContent;// File.OpenRead(path);
multipartContent.ContentType = "application/octet-stream";
multipartContent.transfersyntax = dicomFile.Dataset.InternalTransferSyntax.UID.UID;
multipartContent.FileName = "";
multiContentResult = new MultipartResult("related", boundary) { multipartContent };
return multiContentResult;
}
Mulitpart class and MulticontentResult Class:
public class MultipartContent
{
public string ContentType { get; set; }
public string FileName { get; set; }
public Stream Stream { get; set; }
public string transfersyntax { get; set; }
}
public class MultipartResult : Collection<MultipartContent>, IActionResult
{
private readonly System.Net.Http.MultipartContent content;
public MultipartResult(string subtype = "byteranges", string boundary = null)
{
if (boundary == null)
{
this.content = new System.Net.Http.MultipartContent(subtype);
}
else
{
this.content = new System.Net.Http.MultipartContent(subtype, boundary);
}
}
public async Task ExecuteResultAsync(ActionContext context)
{
foreach (var item in this)
{
if (item.Stream != null)
{
var content = new StreamContent(item.Stream);
if (item.ContentType != null)
{
content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(item.ContentType);
content.Headers.ContentType.Parameters.Add(new System.Net.Http.Headers.NameValueHeaderValue("transfer-syntax", item.transfersyntax));
}
this.content.Add(content);
}
}
context.HttpContext.Response.ContentLength = content.Headers.ContentLength;
context.HttpContext.Response.ContentType = content.Headers.ContentType.ToString();
await content.CopyToAsync(context.HttpContext.Response.Body);
}
}
After sending WAROrs response , I getting error in OHIF viewer in RangeError: offset is out of bounds in stackviewport.js during set pixeldata flat32array to scaledata flat32array like below Image
So I inspect in browser after then I come know that Pixel data size and scaledata size is different like below image..
To verify my dcm file I checked with ohif viewer by directly opened those file in https://v3-demo.ohif.org/local. It is opening properly.
So what are possible reason for this issue ? how to rectify?

Passing images from one page to another in Xamarin Forms

In my app I need to pass images from one page to another page image view to display. I am taking a photo from camera and do some stuffs, then I want to send that images to the second page.
if (await isCamAvailable())
{
MediaFile photo1 = await CrossMedia.Current.TakePhotoAsync(new StoreCameraMediaOptions() { Directory = "NewBusiness", Name = "image1.jpg", PhotoSize = PhotoSize.MaxWidthHeight, MaxWidthHeight = 1024, CompressionQuality = 95 });
if (photo1 != null)
{
PhotoImage1.Source = ImageSource.FromStream(() => { return photo1.GetStream(); });
countList.Remove("a");
countList.Add("a");
}
}
Then I am added it to a string array by doing
private List<string> sendImgList = new List<string>();
sendImgList.Add(createImgByteString(photo1.GetStream()));
private string createImgByteString(Stream data)
{
var bytes = new byte[data.Length];
return Convert.ToBase64String(bytes);
}
Then from second page (for testing i just added only one image)
foreach (string ss in imgList) {
byte[] Base64Stream = Convert.FromBase64String(ss);
imgView.Source = ImageSource.FromStream(() => new MemoryStream(Base64Stream));
}
I followed this example. But image not showing.
https://forums.xamarin.com/discussion/139360/how-to-transfer-images-from-one-page-to-another
Also getting this in logcat..
[0:] ImageLoaderSourceHandler: Image data was invalid: Xamarin.Forms.StreamImageSource05-29 14:22:43.758 W/monodroid-assembly( 8737): typemap: unable to find mapping to a Java type from managed type 'System.Byte, mscorlib'
It seems that you used the Media.Plugin . Why don't you pass the ImageSource directly?
If you do want to convert it to byte array , check the following code
public byte[] GetImageStreamAsBytes(Stream input)
{
var buffer = new byte[16*1024];
using (MemoryStream ms = new MemoryStream())
{
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
return ms.ToArray();
}
}
var imgDate = GetImageStreamAsBytes(photo1.GetStream());
It would be better to pass the byte array directly .
The best mode to pass parameter in pages is with Prism.
https://prismlibrary.com/docs/xamarin-forms/navigation/passing-parameters.html
>
_navigationService.NavigateAsync(new Uri("MainPage", new NavigationParameters
{
{ "key_parameter", image }
})));
And on other page:
>
public override void OnNavigatedTo(INavigationParameters parameters)
{
image = (Image)parameters["key_parameter"];
}

Making screen capture in xamarin.forms

Is there a package that does screen capture in xamarin.forms ?
I need also to capture google maps screen shots
Check out this blog post by Daniel Hindrikes.
I'm going to assume that you use a PCL for your shared code.
You will need to create an interface in your PCL. He calls it IScreenshotManager. The declaration looks like this:
public interface IScreenshotManager
{
Task<byte[]> CaptureAsync();
}
Now all platforms will have their own implementation for it.
For iOS;
public class ScreenshotManager : IScreenshotManager
{
public async System.Threading.Tasks.Task<byte[]> CaptureAsync()
{
var view = UIApplication.SharedApplication.KeyWindow.RootViewController.View;
UIGraphics.BeginImageContext(view.Frame.Size);
view.DrawViewHierarchy(view.Frame, true);
var image = UIGraphics.GetImageFromCurrentImageContext();
UIGraphics.EndImageContext();
using(var imageData = image.AsPNG())
{
var bytes = new byte[imageData.Length];
System.Runtime.InteropServices.Marshal.Copy(imageData.Bytes, bytes, 0, Convert.ToInt32(imageData.Length));
return bytes;
}
}
}
For Android:
public class ScreenshotManager : IScreenshotManager
{
public static Activity Activity { get; set; }
public async System.Threading.Tasks.Task<byte[]> CaptureAsync()
{
if(Activity == null)
{
throw new Exception("You have to set ScreenshotManager.Activity in your Android project");
}
var view = Activity.Window.DecorView;
view.DrawingCacheEnabled = true;
Bitmap bitmap = view.GetDrawingCache(true);
byte[] bitmapData;
using (var stream = new MemoryStream())
{
bitmap.Compress(Bitmap.CompressFormat.Png, 0, stream);
bitmapData = stream.ToArray();
}
return bitmapData;
}
}
And for Windows Phone:
public class ScreenshotManager : IScreenshotManager
{
public async Task<byte[]> CaptureAsync()
{
var rootFrame = Application.Current.RootVisual as PhoneApplicationFrame;
var screenImage = new WriteableBitmap((int)rootFrame.ActualWidth, (int)rootFrame.ActualHeight);
screenImage.Render(rootFrame, new MatrixTransform());
screenImage.Invalidate();
using (var stream = new MemoryStream())
{
screenImage.SaveJpeg(stream, screenImage.PixelWidth, screenImage.PixelHeight, 0, 100);
var bytes = stream.ToArray();
return bytes;
}
}
}
Don't forget to register your platform specific implementations with the attribute which registers it with the Dependency Service, like this:
[assembly: Xamarin.Forms.Dependency (typeof (ScreenshotManager))]
It goes above the namespace declaration.
Now from your shared code you would be able to get the byte[] of a screenshot with a call like this:
var screenshotBytes = DependencyService.Get<IScreenshotManager>().CaptureAsync();
You probably want to check if DependencyService.Get<IScreenshotManager>() isn't null before using it.
After that you can turn your byte[] into an image and do whatever you like with it!
Implementation for UWP
public async Task<byte[]> CaptureAsync()
{
//create and capture Window
var renderTargetBitmap = new RenderTargetBitmap();
await renderTargetBitmap.RenderAsync(Window.Current.Content);
var pixelpuffer = await renderTargetBitmap.GetPixelsAsync();
var logicalDpi = DisplayInformation.GetForCurrentView().LogicalDpi;
IRandomAccessStream stream = new InMemoryRandomAccessStream();
BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, stream);
encoder.BitmapTransform.InterpolationMode = BitmapInterpolationMode.Fant;
encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Straight, (uint)renderTargetBitmap.PixelWidth, (uint)renderTargetBitmap.PixelHeight, logicalDpi, logicalDpi, pixelpuffer.ToArray());
await encoder.FlushAsync();
byte[] resultingBuffer = new byte[stream.Size];
await stream.ReadAsync(resultingBuffer.AsBuffer(), (uint)resultingBuffer.Length, InputStreamOptions.None);
return resultingBuffer;
}

How to add a 'System.Drawing.Image' to a 'System.Web.UI.WebControls.Image'

I have two functions:
Function 1: ImageToByteArray: Is used to Convert an Image into a Byte Array and then Store in an Oracle Database, in a BLOB Field.
public byte[] ImageToByteArray(string sPath)
{
byte[] data = null;
FileInfo fInfo = new FileInfo(sPath);
long numBytes = fInfo.Length;
FileStream fStream = new FileStream(sPath, FileMode.Open, FileAccess.Read);
BinaryReader br = new BinaryReader(fStream);
data = br.ReadBytes((int)numBytes);
return data;
}
Function 2: ByteArrayToImage: Is used to Convert a Byte Array from the Database into an Image:
public System.Drawing.Image ByteArrayToImage(byte[] byteArray)
{
MemoryStream img = new MemoryStream(byteArray);
System.Drawing.Image returnImage = System.Drawing.Image.FromStream(img);
return returnImage;
}
In my Markup I have an Imgage Control:
<asp:Image ID="Image1" runat="server" />
In the Code Behind I want to Assign the Returned Value from Function 2 to (which is of type System.Drawing.Image) to the "image1" control which is of type (System.Web.UI.WebControls.Image).
Obviously I can't just assign:
image1 = ByteArrayToImage(byteArray);
because I'd get the following error: Cannot implicitly convert type 'System.Drawing.Image' to 'System.Web.UI.WebControls.Image'
Is there anyway to do this?
It looks like you just want a simple method to convert an image byte array into a picture. No problem. I found an article that helped me a lot.
System.Web.UI.WebControls.Image image = (System.Web.UI.WebControls.Image)e.Item.FindControl("image");
if (!String.IsNullOrEmpty(currentAd.PictureFileName))
{
image.ImageUrl = GetImage(currentAd.PictureFileContents);
}
else
{
image.Visible = false;
}
//The actual converting function
public string GetImage(object img)
{
return "data:image/jpg;base64," + Convert.ToBase64String((byte[])img);
}
PictureFileContents is a Byte[] and that's what the function GetImage is taking as an object.
You can't. WebControls.Image is just a HTML container for an image url - you can't store the image data directly in it, you just store the reference (url) to an image file.
If you need to retrieve image data dynamically, the usual approach is to create an image handler that will handle the request and return the image as a stream that the browser can display.
See this question
I think it is possible and I hope it be helpful. My solution for this is here:
public System.Web.UI.WebControls.Image HexStringToWebControlImage(string hexString)
{
var imageAsString = HexString2Bytes(hexString);
MemoryStream ms = new MemoryStream();
ms.Write(imageAsString, 0, imageAsString.Length);
if (imageAsString.Length > 0)
{
var base64Data = Convert.ToBase64String(ms.ToArray());
return new System.Web.UI.WebControls.Image
{
ImageUrl = "data:image/jpg;base64," + base64Data
};
}
else
{
return null;
}
}
public byte[] HexString2Bytes(string hexString)
{
int bytesCount = (hexString.Length) / 2;
byte[] bytes = new byte[bytesCount];
for (int x = 0; x < bytesCount; ++x)
{
bytes[x] = Convert.ToByte(hexString.Substring(x * 2, 2), 16);
}
return bytes;
}

Can an ASP.NET MVC controller return an Image?

Can I create a Controller that simply returns an image asset?
I would like to route this logic through a controller, whenever a URL such as the following is requested:
www.mywebsite.com/resource/image/topbanner
The controller will look up topbanner.png and send that image directly back to the client.
I've seen examples of this where you have to create a View - I don't want to use a View. I want to do it all with just the Controller.
Is this possible?
Use the base controllers File method.
public ActionResult Image(string id)
{
var dir = Server.MapPath("/Images");
var path = Path.Combine(dir, id + ".jpg"); //validate the path for security or use other means to generate the path.
return base.File(path, "image/jpeg");
}
As a note, this seems to be fairly efficient. I did a test where I requested the image through the controller (http://localhost/MyController/Image/MyImage) and through the direct URL (http://localhost/Images/MyImage.jpg) and the results were:
MVC: 7.6 milliseconds per photo
Direct: 6.7 milliseconds per photo
Note: this is the average time of a request. The average was calculated by making thousands of requests on the local machine, so the totals should not include network latency or bandwidth issues.
Using the release version of MVC, here is what I do:
[AcceptVerbs(HttpVerbs.Get)]
[OutputCache(CacheProfile = "CustomerImages")]
public FileResult Show(int customerId, string imageName)
{
var path = string.Concat(ConfigData.ImagesDirectory, customerId, "\\", imageName);
return new FileStreamResult(new FileStream(path, FileMode.Open), "image/jpeg");
}
I obviously have some application specific stuff in here regarding the path construction, but the returning of the FileStreamResult is nice and simple.
I did some performance testing in regards to this action against your everyday call to the image (bypassing the controller) and the difference between the averages was only about 3 milliseconds (controller avg was 68ms, non-controller was 65ms).
I had tried some of the other methods mentioned in answers here and the performance hit was much more dramatic... several of the solutions responses were as much as 6x the non-controller (other controllers avg 340ms, non-controller 65ms).
To expland on Dyland's response slightly:
Three classes implement the FileResult class:
System.Web.Mvc.FileResult
System.Web.Mvc.FileContentResult
System.Web.Mvc.FilePathResult
System.Web.Mvc.FileStreamResult
They're all fairly self explanatory:
For file path downloads where the file exists on disk, use FilePathResult - this is the easiest way and avoids you having to use Streams.
For byte[] arrays (akin to Response.BinaryWrite), use FileContentResult.
For byte[] arrays where you want the file to download (content-disposition: attachment), use FileStreamResult in a similar way to below, but with a MemoryStream and using GetBuffer().
For Streams use FileStreamResult. It's called a FileStreamResult but it takes a Stream so I'd guess it works with a MemoryStream.
Below is an example of using the content-disposition technique (not tested):
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult GetFile()
{
// No need to dispose the stream, MVC does it for you
string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "App_Data", "myimage.png");
FileStream stream = new FileStream(path, FileMode.Open);
FileStreamResult result = new FileStreamResult(stream, "image/png");
result.FileDownloadName = "image.png";
return result;
}
This might be helpful if you'd like to modify the image before returning it:
public ActionResult GetModifiedImage()
{
Image image = Image.FromFile(Path.Combine(Server.MapPath("/Content/images"), "image.png"));
using (Graphics g = Graphics.FromImage(image))
{
// do something with the Graphics (eg. write "Hello World!")
string text = "Hello World!";
// Create font and brush.
Font drawFont = new Font("Arial", 10);
SolidBrush drawBrush = new SolidBrush(Color.Black);
// Create point for upper-left corner of drawing.
PointF stringPoint = new PointF(0, 0);
g.DrawString(text, drawFont, drawBrush, stringPoint);
}
MemoryStream ms = new MemoryStream();
image.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
return File(ms.ToArray(), "image/png");
}
You can create your own extension and do this way.
public static class ImageResultHelper
{
public static string Image<T>(this HtmlHelper helper, Expression<Action<T>> action, int width, int height)
where T : Controller
{
return ImageResultHelper.Image<T>(helper, action, width, height, "");
}
public static string Image<T>(this HtmlHelper helper, Expression<Action<T>> action, int width, int height, string alt)
where T : Controller
{
var expression = action.Body as MethodCallExpression;
string actionMethodName = string.Empty;
if (expression != null)
{
actionMethodName = expression.Method.Name;
}
string url = new UrlHelper(helper.ViewContext.RequestContext, helper.RouteCollection).Action(actionMethodName, typeof(T).Name.Remove(typeof(T).Name.IndexOf("Controller"))).ToString();
//string url = LinkBuilder.BuildUrlFromExpression<T>(helper.ViewContext.RequestContext, helper.RouteCollection, action);
return string.Format("<img src=\"{0}\" width=\"{1}\" height=\"{2}\" alt=\"{3}\" />", url, width, height, alt);
}
}
public class ImageResult : ActionResult
{
public ImageResult() { }
public Image Image { get; set; }
public ImageFormat ImageFormat { get; set; }
public override void ExecuteResult(ControllerContext context)
{
// verify properties
if (Image == null)
{
throw new ArgumentNullException("Image");
}
if (ImageFormat == null)
{
throw new ArgumentNullException("ImageFormat");
}
// output
context.HttpContext.Response.Clear();
context.HttpContext.Response.ContentType = GetMimeType(ImageFormat);
Image.Save(context.HttpContext.Response.OutputStream, ImageFormat);
}
private static string GetMimeType(ImageFormat imageFormat)
{
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
return codecs.First(codec => codec.FormatID == imageFormat.Guid).MimeType;
}
}
public ActionResult Index()
{
return new ImageResult { Image = image, ImageFormat = ImageFormat.Jpeg };
}
<%=Html.Image<CapchaController>(c => c.Index(), 120, 30, "Current time")%>
Why not go simple and use the tilde ~ operator?
public FileResult TopBanner() {
return File("~/Content/images/topbanner.png", "image/png");
}
You can write directly to the response but then it isn't testable. It is preferred to return an ActionResult that has deferred execution. Here is my resusable StreamResult:
public class StreamResult : ViewResult
{
public Stream Stream { get; set; }
public string ContentType { get; set; }
public string ETag { get; set; }
public override void ExecuteResult(ControllerContext context)
{
context.HttpContext.Response.ContentType = ContentType;
if (ETag != null) context.HttpContext.Response.AddHeader("ETag", ETag);
const int size = 4096;
byte[] bytes = new byte[size];
int numBytes;
while ((numBytes = Stream.Read(bytes, 0, size)) > 0)
context.HttpContext.Response.OutputStream.Write(bytes, 0, numBytes);
}
}
Below code utilizes System.Drawing.Bitmap to load the image.
using System.Drawing;
using System.Drawing.Imaging;
public IActionResult Get()
{
string filename = "Image/test.jpg";
var bitmap = new Bitmap(filename);
var ms = new System.IO.MemoryStream();
bitmap.Save(ms, ImageFormat.Jpeg);
ms.Position = 0;
return new FileStreamResult(ms, "image/jpeg");
}
UPDATE: There are better options than my original answer. This works outside of MVC quite well but it's better to stick with the built-in methods of returning image content. See up-voted answers.
You certainly can. Try out these steps:
Load the image from disk in to a byte array
cache the image in the case you expect more requests for the image and don't want the disk I/O (my sample doesn't cache it below)
Change the mime type via the Response.ContentType
Response.BinaryWrite out the image byte array
Here's some sample code:
string pathToFile = #"C:\Documents and Settings\some_path.jpg";
byte[] imageData = File.ReadAllBytes(pathToFile);
Response.ContentType = "image/jpg";
Response.BinaryWrite(imageData);
Hope that helps!
Solution 1: To render an image in a view from an image URL
You can create your own extension method:
public static MvcHtmlString Image(this HtmlHelper helper,string imageUrl)
{
string tag = "<img src='{0}'/>";
tag = string.Format(tag,imageUrl);
return MvcHtmlString.Create(tag);
}
Then use it like:
#Html.Image(#Model.ImagePath);
Solution 2: To render image from database
Create a controller method that returns image data like below
public sealed class ImageController : Controller
{
public ActionResult View(string id)
{
var image = _images.LoadImage(id); //Pull image from the database.
if (image == null)
return HttpNotFound();
return File(image.Data, image.Mime);
}
}
And use it in a view like:
# { Html.RenderAction("View","Image",new {id=#Model.ImageId})}
To use an image rendered from this actionresult in any HTML, use
<img src="http://something.com/image/view?id={imageid}>
This worked for me.
Since I'm storing images on a SQL Server database.
[HttpGet("/image/{uuid}")]
public IActionResult GetImageFile(string uuid) {
ActionResult actionResult = new NotFoundResult();
var fileImage = _db.ImageFiles.Find(uuid);
if (fileImage != null) {
actionResult = new FileContentResult(fileImage.Data,
fileImage.ContentType);
}
return actionResult;
}
In the snippet above _db.ImageFiles.Find(uuid) is searching for the image file record in the db (EF context). It returns a FileImage object which is just a custom class I made for the model and then uses it as FileContentResult.
public class FileImage {
public string Uuid { get; set; }
public byte[] Data { get; set; }
public string ContentType { get; set; }
}
you can use File to return a file like View, Content etc
public ActionResult PrintDocInfo(string Attachment)
{
string test = Attachment;
if (test != string.Empty || test != "" || test != null)
{
string filename = Attachment.Split('\\').Last();
string filepath = Attachment;
byte[] filedata = System.IO.File.ReadAllBytes(Attachment);
string contentType = MimeMapping.GetMimeMapping(Attachment);
System.Net.Mime.ContentDisposition cd = new System.Net.Mime.ContentDisposition
{
FileName = filename,
Inline = true,
};
Response.AppendHeader("Content-Disposition", cd.ToString());
return File(filedata, contentType);
}
else { return Content("<h3> Patient Clinical Document Not Uploaded</h3>"); }
}
Look at ContentResult. This returns a string, but can be used to make your own BinaryResult-like class.
if (!System.IO.File.Exists(filePath))
return SomeHelper.EmptyImageResult(); // preventing JSON GET/POST exception
else
return new FilePathResult(filePath, contentType);
SomeHelper.EmptyImageResult() should return FileResult with existing image (1x1 transparent, for example).
This is easiest way if you have files stored on local drive.
If files are byte[] or stream - then use FileContentResult or FileStreamResult as Dylan suggested.
I see two options:
1) Implement your own IViewEngine and set the ViewEngine property of the Controller you are using to your ImageViewEngine in your desired "image" method.
2) Use a view :-). Just change the content type etc.
You could use the HttpContext.Response and directly write the content to it (WriteFile() might work for you) and then return ContentResult from your action instead of ActionResult.
Disclaimer: I have not tried this, it's based on looking at the available APIs. :-)
I also encountered similar requirement,
So in my case I make a request to Controller with the image folder path, which in return sends back a ImageResult object.
Following code snippet illustrate the work:
var src = string.Format("/GenericGrid.mvc/DocumentPreviewImageLink?fullpath={0}&routingId={1}&siteCode={2}", fullFilePath, metaInfo.RoutingId, da.SiteCode);
if (enlarged)
result = "<a class='thumbnail' href='#thumb'>" +
"<img src='" + src + "' height='66px' border='0' />" +
"<span><img src='" + src + "' /></span>" +
"</a>";
else
result = "<span><img src='" + src + "' height='150px' border='0' /></span>";
And in the Controller from the the image path I produce the image and return it back to the caller
try
{
var file = new FileInfo(fullpath);
if (!file.Exists)
return string.Empty;
var image = new WebImage(fullpath);
return new ImageResult(new MemoryStream(image.GetBytes()), "image/jpg");
}
catch(Exception ex)
{
return "File Error : "+ex.ToString();
}
Read the image, convert it to byte[], then return a File() with a content type.
public ActionResult ImageResult(Image image, ImageFormat format, string contentType) {
using (var stream = new MemoryStream())
{
image.Save(stream, format);
return File(stream.ToArray(), contentType);
}
}
}
Here are the usings:
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using Microsoft.AspNetCore.Mvc;
Yes you can return Image
public ActionResult GetImage(string imageFileName)
{
var path = Path.Combine(Server.MapPath("/Images"), imageFileName + ".jpg");
return base.File(path, "image/jpeg");
}
(Please don't forget to mark this as answer)
From a byte[] under Core 3.2, you can use:
public ActionResult Img(int? id) {
MemoryStream ms = new MemoryStream(GetBytes(id));
return new FileStreamResult(ms, "image/png");
}

Resources