How do I save a bitmap to my database? - asp.net-mvc

I have an bitmap in System.Drawing. I know it must be converted to a byte[] to be stored in my table.
My table field:
public class Task
public byte? TaskImage { get; set; }
I have this in line code so far:
MemoryStream ms = new MemoryStream();
mybmp.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
Task.TaskImage =
db.SaveChanges();
I've been referenced to this:
public static byte[] ImageToByteArray(Image image)
{
var memoryStream = new MemoryStream();
image.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Jpeg); // consider format
return memoryStream.ToArray();
}
but can't figure out how to apply it. This attempt doesn't work.
Task.TaskImage = Image.FromStream(ms.ToArray())
Can someone provide the code to go from the System.Drawing to Task.TaskImage= in inline code, or how to reference the function ImageToByteArray(Image image) in my code? In my MVC project, where is the proper place to put this function ImageToByteArray(Image image) if used?

You're on the right track.
One mistake I see is that
public byte? TaskImage { get; set; }
Needs to be a byte array. That is only a single nullable byte. Change it to
public byte[] TaskImage { get; set; }
What is an image and how do we store it?
In it's simplest form, an image is just a series of bits that are organised in a particular way (like any virtual object stored on a computer).
Databases aren't very good at storing complex types of data; they typically store strings (varchar, for example), integers of various sizes, floating point numbers, boolean values (a bit) and so on. In order to store something complex like an image we have to split the image up in to bytes and give that to the database (they can handle bytes (groups of bits) easily). You seem to know all of this.
In order to save an image to the database we need to know what format it's in and we need to be able to read all the bytes of the image.
Streams (What is a stream?) are useful here. They allow us to read and write a sequence of bytes. .NET classes like Image may also be useful for loading information about an image.
Reading an image from a database
Suppose we have an image stored as a byte array in a database. Entity Framework loads the object for us as a Task object.
public class Task
{
public byte[] TaskImage { get; set; }
}
To load the image:
Task task;
var ms = new MemoryStream(task.TaskImage);
Image img = Image.FromStream(ms);
Or
Bitmap bmp = new Bitmap(ms);
Saving an image to a database
Task task = new Task();
MemoryStream ms = new MemoryStream();
Image img = Image.FromFile("...");
img.Save(ms, img.RawFormat);
ms.Position = 0;
task.TaskImage = new byte[ms.Length];
ms.Read(TaskImage, 0, (int)ms.Length);
dbContext.Tasks.Add(task);
dbContext.SaveChanges();

Related

Add a Class with byte[] to NSUserDefaults in iOS Share Extension (Xamarin)

In Xamarin.iOS Share Extension, I'd like to store my selected files (like pdf, images, word etc.) in my NSUserDefaults and when the main application starts, I'll have access to the files stored in it.
Here is my file class :
public class MyClass {
public string FileName { get; set; }
public byte[] Content { get; set; }
}
So in LoadItem in DidSelectPost methods, I create by object by using byte[] of files. Then for saving datas in NSUserDefaults, I convert my object to JSON like this (by using Newtonsoft.Json library):
string jsonString = JsonConvert.SerializeObject(myFileObject);
and I set it to NSUserDefaults object like that:
NSUser.SetValueForKey(new NSString(myFileObject), new NSString("FileSharing" + count));
or
NSUser.SetValueForKey(new NSString(myFileObject), new NSString("FileSharing"+ count));
And after I'll synchronise my items : NSUser.Synchronize());
Everything goes well, but when the main application open, the new data is not here.
string toDesralize = nSUser.StringForKey("FileSharing0");
I've tried for many files, and I've found out that this issue works only for files with low height and it doesn't work for files like 14mb. How can i save files with high height in NSUserDefaults? Is there any other way for doing the same job ?
You can use file system to store and read data in Xamarin.iOS:
var documents = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
var filename = Path.Combine(documents, "Write.txt");
//save text
File.WriteAllText(filename, "Write this text into a file");
//save bytes
File.WriteAllBytes(filename,yourBytes);
And the read methods:
var text = File.ReadAllText("TestData/ReadMe.txt");
Console.WriteLine(text);
var bytes = File.ReadAllBytes("path");

The binary image can't display on view asp.net core 2.x

I upload an image into a table with byte[] format. My problem is, that when I retrieve that on a view, the image won't show up.
Model
{
public byte[] image {get; set;}
}
Controller
public async Task<IActionResult> Create(Profile profile, IFormFile image)
{
if (ModelState.IsValid)
{
using (var memoryStream = new MemoryStream())
{
image.CopyTo(memoryStream);
profile.image = memoryStream.ToArray();
}
_context.Add(image);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(image);
}
View
<img src="#item.image" />
You cannot simply dump a byte array as the source of an HTML image tag. It has to be a URI. That typically means that you need an action that retrieves the image data from the database and returns it as file:
[HttpGet("profileimage")]
public async Task<IActionResult> GetProfileImage(int profileId)
{
var profile = _context.Profiles.FindAsync(profileId);
if (profile?.image == null) return NotFound();
return File(profile.image, "image/jpeg");
}
Then, you can do something like:
<img src="#Url.Action("GetProfileImage", new { profileId = item.Id })" />
Alternatively, you can use a Data URI. However, this will result in the entire image data being included in your HTML document, increasing the overall download time of the document and delaying rendering. Additionally, Data URIs must be Base64 encoded, which effectively increases the image size roughly 1.5 times. For small, simple images, it's not too big of a deal, but you definitely should avoid this approach with larger images. Anyways, doing this would look something like:
<img src="data:image/jpeg;base64,#Convert.ToBase64String(item.image)" />

Easiest way of porting html table data to readable document

Ok,
For the past 6 months i've been struggeling to build a system that allows user input in form of big sexy textareas(with loads of support for tables,list etc). Pretty much enables the user to input data as if it were word. However when wanting to export all this data I haven't been able to find a working solution...
My first step was to try and find a reporting software that did support raw HTML from the data source and render it as normal html, worked perfectly except that the keep together function is awful, either data is split in half(tables,lists etc) which I dont want. Or report always skips to the next page to avoid this, ending up in 15+ empty pages within the final document.
So Im looking for some kind of tip/direction to what would be the best solution to export my data into a readable document(pdf or word pref).
What I got is the following data breakdown, where data is often raw html.
-Period
--Unit
---Group
----Question
-----Data
What would be the best choice? Trying to render html to pdf or rtf? I need tips :(
And also sometimes the data is 2-3 pages long with mixed tables lists and plain text.
I would suggest that you try to keep this in the browser, and add a print stylesheet to the HTML to make it render one way on the screen and another way on paper. Adding a print stylesheet to your HTML is as easy as this:
<link rel="stylesheet" media="print" href="print.css">
You should be able to parse the input it with something like Html Agility Pack and transform it (i.e. with XSLT) to whatever output format you want.
Another option is to write HTML to the browser, but with Content-Type set to a Microsoft Word-specific variant (there are several to choose from, depending on the version of Word you're targeting) should make the browser ask if the user wants to open the page with Microsoft Word. With Word 2007 and newer you can also write Office Open XML Word directly, since it's XML-based.
The content-types you can use are:
application/msword
For binary Microsoft Word files, but should also work for HTML.
application/vnd.openxmlformats-officedocument.wordprocessingml.document
For the newer "Office Open XML" formats of Word 2007 and newer.
A solution you could use is to run an application on the server using System.Diagnostics.Process that will convert the site and save it as a PDF document.
You could use wkhtmltopdf which is an open source console program that can convert from HTML to PDF or image.
The installer for windows can be obtained from wkhtmltox-0.10.0_rc2 Windows Installer (i368).
After installing wkhtmltopdf you can copy the files in the installation folder inside your solution. You can use a setup like this in the solution:
The converted pdf's will be saved to the pdf folder.
And here is code for doing the conversion:
var wkhtmltopdfLocation = Server.MapPath("~/wkhtmltopdf/") + "wkhtmltopdf.exe";
var htmlUrl = #"http://stackoverflow.com/q/7384558/750216";
var pdfSaveLocation = "\"" + Server.MapPath("~/wkhtmltopdf/pdf/") + "question.pdf\"";
var process = new Process();
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.FileName = wkhtmltopdfLocation;
process.StartInfo.Arguments = htmlUrl + " " + pdfSaveLocation;
process.Start();
process.WaitForExit();
The htmlUrl is the location of the page you need to convert to pdf. It is set to this stackoverflow page. :)
Its a general question, but two things come to mind the Visitor Pattern and Changing the Mime Type.
Visitor Pattern
You can have two seperate rendering techniques. This would be up to your implementation.
MIME Type
When the request is made write date out in the Response etc
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.Charset = "utf-16";
HttpContext.Current.Response.ContentEncoding = System.Text.Encoding.GetEncoding("windows-1250");
HttpContext.Current.Response.AddHeader("content-disposition", string.Format("attachment; filename={0}.doc", filename));
HttpContext.Current.Response.ContentType = "application/msword";
HttpContext.Current.Response.Write("-Period");
HttpContext.Current.Response.Write("/n");
HttpContext.Current.Response.Write("--Unit");
HttpContext.Current.Response.Write("/n");
HttpContext.Current.Response.Write("---Group");
HttpContext.Current.Response.Write("/n");
HttpContext.Current.Response.Write("----Question");
HttpContext.Current.Response.Write("/n");
HttpContext.Current.Response.Write("-----Data");
HttpContext.Current.Response.Write("/n");
HttpContext.Current.Response.End();
Here is another option, use print screens (Although it doesnt take care of scrolling, I think you should be able to build this in). This example can be expanded to meet the needs of your business, although it is a hack of sorts. You pass it a URL it generates an image.
Call like this
protected void Page_Load(object sender, EventArgs e)
{
int screenWidth = Convert.ToInt32(Request["ScreenWidth"]);
int screenHeight = Convert.ToInt32(Request["ScreenHeight"]);
string url = Request["Url"].ToString();
string bitmapName = Request["BitmapName"].ToString();
WebURLToImage webUrlToImage = new WebURLToImage()
{
Url = url,
BrowserHeight = screenHeight,
BrowserWidth = screenWidth,
ImageHeight = 0,
ImageWidth = 0
};
webUrlToImage.GenerateBitmapForUrl();
webUrlToImage.GeneratedImage.Save(Server.MapPath("~") + #"Images\" +bitmapName + ".bmp");
}
Generate an image from a webpage.
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Threading;
using System.IO;
public class WebURLToImage
{
public string Url { get; set; }
public Bitmap GeneratedImage { get; private set; }
public int ImageWidth { get; set; }
public int ImageHeight { get; set; }
public int BrowserWidth { get; set; }
public int BrowserHeight { get; set; }
public Bitmap GenerateBitmapForUrl()
{
ThreadStart threadStart = new ThreadStart(ImageGenerator);
Thread thread = new Thread(threadStart);
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
thread.Join();
return GeneratedImage;
}
private void ImageGenerator()
{
WebBrowser webBrowser = new WebBrowser();
webBrowser.ScrollBarsEnabled = false;
webBrowser.Navigate(Url);
webBrowser.DocumentCompleted += new
WebBrowserDocumentCompletedEventHandler(webBrowser_DocumentCompleted);
while (webBrowser.ReadyState != WebBrowserReadyState.Complete)
Application.DoEvents();
webBrowser.Dispose();
}
void webBrowser_DocumentCompleted(object sender,
WebBrowserDocumentCompletedEventArgs e)
{
WebBrowser webBrowser = (WebBrowser)sender;
webBrowser.ClientSize = new Size(BrowserWidth, this.BrowserHeight);
webBrowser.ScrollBarsEnabled = false;
GeneratedImage = new Bitmap(webBrowser.Bounds.Width, webBrowser.Bounds.Height);
webBrowser.BringToFront();
webBrowser.DrawToBitmap(GeneratedImage, webBrowser.Bounds);
if (ImageHeight != 0 && ImageWidth != 0)
GeneratedImage =
(Bitmap)GeneratedImage.GetThumbnailImage(ImageWidth, ImageHeight,
null, IntPtr.Zero);
}
}

Processing an uploaded file without saving it?

I am uploading a file using the following code
[HttpPost]
public ActionResult ImportDeleteCourse(ImportFromExcel model)
{
var excelFile = model.ExcelFile;
if (ModelState.IsValid)
{
OrganisationServices services = new OrganisationServices();
string filePath = Path.Combine(HttpContext.Server.MapPath("../Uploads"),
Path.GetFileName(excelFile.FileName));
excelFile.SaveAs(filePath);
// ... snipped //
}
}
I do not really need to do store the uploaded excel file. Is there anyway I can process it without saving?
Note: The ImportFromExcel class is nothing but a model, which is basically:
public class ImportFromExcel
{
[Required(ErrorMessage = "Please select an Excel file to upload.")]
[DisplayName("Excel File")]
public HttpPostedFileWrapper ExcelFile { get; set; }
}
The most interesting part is that it wraps a HttpPostedFileWrapper.
Sure you can. As Patko suggested, the InputStream property can be used for another stream. For example I did this for an uploaded xml document to use with LINQ to XML:
XDocument XmlDoc = XDocument.Load(new StreamReader(viewmodel.FileUpload.InputStream))
Cheers,
Chris
The HttpPostedFileBase.InputStream property looks promising. You should be able to use that and save the data to whichever other stream you need to.

Model binding HttpPostedFileBase and then storing the file to datastore

ASP.NET MVC seems to correctly automatically bind between HTML form's file input field and HttpPostedFileBase. On the other hand it cannot bind from file input field to byte array..I tried and it issues exception - something about not being able to convert to Base64. I had only the byte array property on my Model classes previously because later on I need it to perform serialization of the object into XML file.
Now I've come up with this workaround and it works fine but I am not sure if this will be ok:
[DataContract]
public class Section : BaseContentObject
{
...
[DataMember]
public byte[] ImageBytes;
private HttpPostedFileBase _imageFile;
public HttpPostedFileBase ImageFile
{
get { return _imageFile; }
set
{
_imageFile = value;
if (value.ContentLength > 0)
{
byte[] buffer = new byte[value.ContentLength];
value.InputStream.Read(buffer, 0, value.ContentLength);
ImageBytes = buffer;
ImageType = value.ContentType;
}
}
}
[DataMember]
public string ImageType { get; set; }
}
I think you are letting your Model connect to closely with your Controller. The usual way to do this is:
public ActionResult AcceptFile(HttpPostedFileBase submittedFile) {
var bytes = submittedFile.FileContents;
var model = new DatabaseThing { data = bytes };
model.SaveToDatabase();
}
In this case, there is no need for your Model to be aware of HttpPostedFileBase, which is strictly an ASP.NET concept.
If you need complex binding beyond what the DefaultModelBinder supplies (which is alot), the usual way is to register specialized ModelBinders in Global.asax and then accept your own Model classes as Action Method arguments, like so:
In Global.asax:
ModelBinders.Binders.Add(typeof(MyThing), new ThingModelBinder());
This ModelBinder could then, for example, find any file that was posted with the form and bind the contents of that file to the Data property of your Thing.
And in your Controller:
public ActionResult AcceptThing(MyThing thing) {
thing.Data.SaveToDatabase();
}
In this Action Method, your ThingModelBinder would have handled all binding, making it transparent to both the Controller and the Model.
Modifying your actual Model classes to be aware of, and function with, ASP.NET would not be necessary in this case. Your Model classes are, after all, supposed to represent your actual data.
Apparently there are huge changes (just found it out) in MVC Futures 2, especially regarding Model Binders.
For instance, the problem with my input file binding to byte array, there is a binder now:
• BinaryDataModelBinderProvider – Handles binding base-64 encoded input to byte[] and System.Linq.Data.Binary models.

Resources