I have a monitoring system and I want to save a snapshot from a camera when alarm trigger. I have tried many methods to do that…and it’s all working fine.
string ImageName = #"E:\snapshot\pic" + imageid + ".jpg";
WebClient webclient = new WebClient();
webclient.Credentials = new NetworkCredential("admin", "pass");
Uri url = new Uri("http://" + ip + "/cgi-bin/cmd/encoder?SNAPSHOT");
webclient.DownloadFileAsync(url, ImageName);
webclient.Dispose();
the image coming from the cam is(1280*1024). i want to crop the image to get (500*500) Pixel
private void button2_Click(object sender, EventArgs e)
{
string ImageFrom = #"c:\3.jpg";
byte[] imageData = ReadFile(ImageFrom);
byte[] data = CropPicture(imageData, 500, 500);
SqlConnection cn = new SqlConnection("Data Source=.;Initial Catalog=test;Integrated Security=True");
string qry = "insert into val (id,img) values (#OriginalPath, #ImageData)";
SqlCommand SqlCom = new SqlCommand(qry, cn);
SqlCom.Parameters.Add(new SqlParameter("#OriginalPath",(object)"123"));
SqlCom.Parameters.Add(new SqlParameter("#ImageData", (object)data));
cn.Open();
SqlCom.ExecuteNonQuery();
}
byte[] ReadFile(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;
}
public static byte[] CropPicture(byte[] imgFile, int targetW, int targetH)
{
Image imgPhoto = Image.FromStream(new MemoryStream(imgFile));
int targetX = (imgPhoto.Width - targetW) / 2;
int targetY = (imgPhoto.Height - targetH) / 2;
Bitmap bmpPhoto = new Bitmap(targetW, targetH, PixelFormat.Format24bppRgb);
bmpPhoto.SetResolution(80, 60);
Graphics gfxPhoto = Graphics.FromImage(bmpPhoto);
gfxPhoto.SmoothingMode = SmoothingMode.AntiAlias;
gfxPhoto.InterpolationMode = InterpolationMode.HighQualityBicubic;
gfxPhoto.PixelOffsetMode = PixelOffsetMode.HighQuality;
gfxPhoto.DrawImage(imgPhoto, new Rectangle(0, 0, targetW, targetH), targetX, targetY, targetW, targetH, GraphicsUnit.Pixel);
MemoryStream mm = new MemoryStream();
bmpPhoto.Save(mm, System.Drawing.Imaging.ImageFormat.Jpeg);
// Dispose of all the objects to prevent memory leaks
imgPhoto.Dispose();
bmpPhoto.Dispose();
gfxPhoto.Dispose();
return mm.GetBuffer();
}
then insert it in the sql database
i got a code to crop the image.and i know how to insert image into sql database
but it all need to read the image as a file in the pc.
i stream the image then save it
then get it and crop it and insert it into db
PLEASE can any one tell me how to get the stream without the need to save it
You should be able to use something like this... (not tested)
Image img = Image.FromStream((new WebClient()).OpenRead("a"));
Related
private void Msg1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
string SaveFileTo = "D:\\DA.jpg";
// string SaveFileTo = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
// string filename = "jmk.jpg";
// SaveFileTo = Path.Combine(SaveFileTo, filename);
CN.Open();
SqlCommand cmd = new SqlCommand("select photo from edistindata where enrollno='" + CboEnroll.Text + "' ", CN);
DR = cmd.ExecuteReader();
byte[] data = null;
while (DR.Read())
{
data = (byte[])DR["Photo"];
}
using (var fs = new FileStream(SaveFileTo, FileMode.Create, FileAccess.Write))
{
fs.Write(data,0,data.Length);
}
MessageBox.Show("Success");
}
I have run the code in the question, even it has some of not good coding practices, if the data in the photo column is not corrupted it should produce the image file.
so I have put down your code with proper enhancements that will flag you early before saving corrupted data.
private void Msg1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
ImageCodecInfo theJpgCodecInfo = ImageCodecInfo.GetImageEncoders()
.FirstOrDefault(encoder => encoder.MimeType == "image/jpeg");
var myEncoder = Encoder.Quality;
var myEncoderPrams = new EncoderParameters(1);
myEncoderPrams.Param[0] = new EncoderParameter(myEncoder, 100L);
string SaveFileTo = "D:\\DA";
// string SaveFileTo = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
// string filename = "jmk.jpg";
// SaveFileTo = Path.Combine(SaveFileTo, filename);
CN.Open();
SqlCommand cmd = new SqlCommand("select photo from edistindata where
enrollno=#Enrol;", CN);
cmd.Parameters.AddWithValue("#Enrol", CboEnroll.SelectedItem.ToString());
DR = cmd.ExecuteReader();
byte[] data = null;
int idx = 0;
while (DR.Read())
{
data = (byte[])DR["Photo"];
Image tempImage;
try
{
tempImage = ByteArrayToImage(data);
}
catch (Exception exc)
{
MessageBox.Show(exc.GetType().ToString()
+Environment.NewLine+exc.Message);
continue;
}
var tempBitmap = new Bitmap(tempImage);
var tempFname = "D:\\DA"+(idx++).ToString()+".jpg";
tempBitmap.Save(tempFname, theJpgCodecInfo, myEncoderPrams);
}
}
public static Image ByteArrayToImage(byte[] byteArrayIn)
{
using (MemoryStream ms = new MemoryStream(byteArrayIn))
{
Image returnImage = Image.FromStream(ms);
return returnImage;
}
}
The enhancements that I suggested as follow:
As #derpirscher mentioned in his comment use parameters not string concatenation when building SQL commands and the easiest most lazy way to do it is Parameters.AddWithValue().
Use CboBox.SelectedItem.ToString in place of the .Text as been in your code.
instead of dumping the byte[] directly through a FileStream.Write() I transferred the byte array into Image() then into Bitmap().
this way if the byte[] (and hence the data in the db column photo) is not one of the binary formats the the class Image() can handle it will throw exception and I used that to show the related error.
Also, this way we over came some issues that may rise if we used Bitmap() directly if the data byte[] contains PNG format.
No matter what image format is stored in the photo column it will be legitimately re-encoded as Jpeg then saved.
before now, i save 2 size of image in database, real size and thumbnail, then show each of them when i need.
in ashx handler i set which type i need, here is my code:
string field = context.Request.QueryString["field"];
string table = context.Request.QueryString["table"];
string id = context.Request.QueryString["id"];
string conn = ConfigurationManager.ConnectionStrings["LocalSqlServer"].ConnectionString;
SqlConnection myConnection = new SqlConnection(conn);
myConnection.Open();
string sql = "";
sql = "Select " + field + ", pictureType from " + table + " where id=#imageId";
SqlCommand cmd = new SqlCommand(sql, myConnection);
cmd.Parameters.Add("#imageId", SqlDbType.Int).Value = id;
cmd.Prepare();
SqlDataReader dr = cmd.ExecuteReader();
dr.Read();
context.Response.ContentType = dr["pictureType"].ToString();
context.Response.BinaryWrite((byte[])dr[field]);
dr.Close();
myConnection.Close();
and i use this way:
<img src="handlers/ShowPic.ashx?table=tblEnBackGrounds&field=image&id=1" alt="s" />
but now i decide to save just real size image, then in ashx file re size and show proper type(here real or thumbnail).
now i need first to now is it good or not? second i don't have any idea how to re size binary data before show in ashx handler
Use the great Image Resize lib http://imageresizing.net/.
You need to resize images proportionally and keep their aspect ratio. Using the Image resize lib, something like this could be the function to do the job:
public static byte[] resizeProportionaly(byte[] imageFile, int pWidth, int pHeight, string crop = "&crop=auto")
{
MemoryStream stream = new MemoryStream(imageFile);
stream.Seek(0, SeekOrigin.Begin);
ResizeSettings resizeCropSettings = new ResizeSettings(string.Format("bgcolor=FFFFFF&width={0}&height={1}&format=jpg" + crop, pWidth, pHeight));
Image originalImage = Image.FromStream(stream, true, false);
Image resizedImage = ImageBuilder.Current.Build(originalImage, resizeCropSettings);
MemoryStream ms = new MemoryStream();
resizedImage.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
return ms.ToArray();
}
and in your handler something like this:
public void ProcessRequest (HttpContext context) {
// some init code...take care of your query strings here etc.
string cropString = "x1,y1,x2,y2"; // if you need croping?
// change height and width based on your picture type
int outWidth = 640; // whatever you need here
int outHeight = 480;
System.Data.DataRow data = GetDBPhotoRecord(photoId);
byte[] photoStream = (byte[])data[mxmPhotos.Photo];
// if you dont need cropping just remove the last cropString parameter
byte[] outStream = resizeProportionaly(photoStream, outWidth, outHeight, cropString);
// ...
context.Response.Buffer = true;
context.Response.Clear();
context.Response.ContentType = "image/jpeg";
context.Response.Cache.SetCacheability(HttpCacheability.Public);
context.Response.Cache.SetExpires(DateTime.UtcNow.AddDays(7));
context.Response.BinaryWrite(outStream);
}
The following HttpHandler is to retrieve image from database. When I initially tested it it was working fine. but now the problem is that it still retieve image but does not display it in image control that is in Listview.
`public void ProcessRequest (HttpContext context)
{
string imageid = context.Request.QueryString["ImID"];
using (SqlConnection connection = ConnectionManager.GetConnection())
{
SqlCommand command = new SqlCommand("select Normal_Thumbs from User_Images where Id=" + imageid, connection);
SqlDataReader dr = command.ExecuteReader();
dr.Read();
if (dr[0] != DBNull.Value)
{
Stream str = new MemoryStream((Byte[])dr[0]);
Bitmap Photo = new Bitmap(str);
int Width = Photo.Width;
int Height = Photo.Height;
int imagesize = 200;
if (Photo.Width > Photo.Height)
{
Width = imagesize;
Height = Photo.Height * imagesize / Photo.Width;
}
else
{
Width = Photo.Width * imagesize / Photo.Height;
Height = imagesize;
}
Bitmap bmpOut = new Bitmap(150, 150);
Graphics g = Graphics.FromImage(bmpOut);
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
g.FillRectangle(Brushes.White, 0, 0, Width, Height);
g.DrawImage(Photo, 0, 0, Width, Height);
MemoryStream ms = new MemoryStream();
bmpOut.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
byte[] bmpBytes = ms.GetBuffer();
bmpOut.Dispose();
ms.Close();
context.Response.Write(bmpBytes);
context.Response.End();
}
}
}
The Handler Retrieves the image but the listview does not display it.
Try this approach, setting content type to the response.
...
context.Response.Clear();
context.Response.ContentType = System.Drawing.Imaging.ImageFormat.Png.ToString();
context.Response.OutputStream.Write(bmpBytes, 0, bmpBytes.Length);
context.Response.End();
...
Regards.
For Save Image I am try this code.
MySqlConnection mycon = new MySqlConnection(string.Format("Server=127.0.0.1;Port=3306;Database=test;Uid=root;Pwd=123456;"));
mycon.Open()
FileStream fs = new FileStream("b.jpg", FileMode.Open, FileAccess.Read);
int sizee = (int)fs.Length;
byte[] rawData = new byte[sizee+1];
fs.Read(rawData, 0, sizee);
fs.Close();
new MySqlCommand(string.Format("INSERT INTO image VALUES(NULL,'{0}',{1})", rawData, sizee), mycon).ExecuteNonQuery();
This code is work fine and insert data successfully.But when i trying to retrieve data it throw an exception No imaging component suitable to complete this operation was found.
Here is the code which is use to retrieve data.
MySqlConnection mycon = new MySqlConnection(string.Format("Server=127.0.0.1;Port=3306;Database=test;Uid=root;Pwd=123456;"));
mycon.Open();
MySqlCommand mycom = new MySqlCommand("Select * from image", mycon);
MySqlDataReader myData = mycom.ExecuteReader();
myData.Read();
int filesize = myData.GetInt32(myData.GetOrdinal("size"));
byte[] mydatya=new byte[filesize];
myData.GetBytes(myData.GetOrdinal("myImage"), 0, mydatya, 0, filesize);
var bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.StreamSource = new MemoryStream(mydatya);
bitmapImage.EndInit();
It is generally considered better practice to put only references to files in a database and physically save the files in a folder.
I have a code to stream a snapshot from an IP camera and save it on harddisk.
Then I have another code to read it and store it in ms-sql database.
I know that it will be more faster if I just stream the image and save it in the database without saving it on the harddisk and read it again. But I don't know how to merge this.
Code to get the image
string sourceURL = "http://" + ip + "/cgi-bin/cmd/encoder?SNAPSHOT";
WebRequest req = (WebRequest)WebRequest.Create(sourceURL);
req.Credentials = new NetworkCredential("admin", "123456");
WebResponse resp = req.GetResponse();
Stream stream = resp.GetResponseStream();
Bitmap bmp = (Bitmap)Bitmap.FromStream(stream);
bmp.Save(ImagePath);
Then to insert the image to the database:
byte[] imageData = ReadFile(ImageName);
using (SqlConnection cn = new SqlConnection(constr))
{
string qry = "update vaiolations set val_image=#ImageData ,valid=1 where id=#OriginalPath ";
SqlCommand SqlCom = new SqlCommand(qry, cn);
SqlCom.Parameters.Add(new SqlParameter("#OriginalPath", (object)id));
SqlCom.Parameters.Add(new SqlParameter("#ImageData", (object)imageData));
cn.Open();
SqlCom.ExecuteNonQuery();
cn.Close();
cn.Dispose();
}
byte[] ReadFile(string sPath)
{
using (FileStream fStream = new FileStream(sPath, FileMode.Open, FileAccess.Read))
{
byte[] data = null;
FileInfo fInfo = new FileInfo(sPath);
long numBytes = fInfo.Length;
BinaryReader br = new BinaryReader(fStream);
data = br.ReadBytes((int)numBytes);
return data;
}
}
How can I combine these two code snippets to stream the image and then immediately insert it into the database?
Why are you converting the incoming bytes to a Bitmap?
You could probably just read the stream to a memory stream, and pass it on to the database:
Stream stream = resp.GetResponseStream();
byte[] data;
using (MemoryStream ms = new MemoryStream())
{
int num_bytes = 0;
byte[] temp = new byte[4096];
while ((num_bytes = stream.Read(temp, 0, temp.Length)) > 0)
ms.Write(temp, 0, bytes);
data = ms.ToArray();
}
Then pass data to your database.