HTTPHandler write Binary Data to Response , load image - c#

iv'e got a repeater bonded to a list of entities
BL_Engine engine = (BL_Engine)Application["engine"];
List<AppProduct> products = engine.Get_Products();
Repeater1.DataSource = products;
Repeater1.DataBind();
iv'e also got a user control i use to represent these product entities , i do this by overriding the Databind() in the user control :
public override void DataBind()
{
AppProduct product = (Page.GetDataItem() as AppProduct);
lbl_title.Text = product.Title;
lbl_short.Text = product.Short;
lbl_date.Text = product.Date.ToShortDateString();
Session["current_img"] = product.Image1;
base.DataBind();
}
in my HttpHanlder object kept in a .ashx file i write the image to the response
the response happens only once so only the last picture is written to (ALL) the user controls.
public void ProcessRequest(HttpContext context)
{
byte [] image = (byte[])context.Session["current_img"];
context.Response.ContentType = "image/bmp";
context.Response.OutputStream.Write(image, 0, image.Length);
}
any idea how i could write the binary data for each individual control
thanks in advance
eran.

Let me suggest a different approach.
Declare a regular html image element in your control and set the "runat=server" property as so:
<img src="" runat="server" id="img_product" />
Then change your DataBind() method to do this instead:
public override void DataBind()
{
AppProduct product = (Page.GetDataItem() as AppProduct);
lbl_title.Text = product.Title;
lbl_short.Text = product.Short;
lbl_date.Text = product.Date.ToShortDateString();
img_product.src= "\"data:image/jpg;base64,"+System.Convert.ToBase64String(product.Image1)+"\"";
base.DataBind();
}
And get rid of the HTTPHandler. You don't need it for this.

Change your handler so that it takes the id of the current product as a query string parameter. In the handler load the correct image data based on the parameter and write that instead.

well to conclude , for this case i think the best practice would be #icarus's answer ,
not the disregard #kmcc049's answer i just hadn't dug into it since it seemed like a more complicated architecture for my app.
in this case DROP THE HTTPHANDLER .
i saved the image's type , and data from the post file.
public enum ImageType : byte {jpg,jpeg,png,gif}
private byte[] Get_Image(HttpPostedFile file)
{
ImageType type = GetType(file.ContentType);
if (file.InputStream.Length <= 1)
return null;
byte[] imageData = new byte[file.InputStream.Length + 1 + 1];
file.InputStream.Read(imageData, 1, imageData.Length+1);
imageData[0] =(byte)type;
return imageData;
}
private ImageType GetType(string _type)
{
ImageType t = default(ImageType);
string s = _type.Substring(_type.IndexOf('/')+1).ToLower() ;
switch (s)
{
case "jpg": t = ImageType.jpg;
break;
case "jpeg": t = ImageType.jpeg;
break;
case "png": t = ImageType.png;
break;
case "gif": t = ImageType.gif;
break;
}
return t;
}
then i extracted and added it to the user control in my DataBind override(in my user control) :
public override void DataBind()
{
AppProduct product = (Page.GetDataItem() as AppProduct);
img_main.Attributes.Add("src",Build_Img_Data(product.Image1));
base.DataBind();
}
private string Build_Img_Data(byte[] imageData)
{
ImageType type = (ImageType)imageData[0] ;
byte[] new_imageData = new byte[imageData.Length - 1];
Array.ConstrainedCopy(imageData, 1, new_imageData, 0, new_imageData.Length);
MemoryStream ms = new MemoryStream(new_imageData);
string base64String = string.Format("data:image/{0};base64,{1}",type.ToString(),Convert.ToBase64String(ms.ToArray()));
return base64String;
}

Related

Sending Base64 Image to server and then pulling from the server to display later Xamarin

I am new to Xamarin Andriod Development. I am trying to send a Base64 encoded image to mySQL server database and then retrieving the Base64 encoded image in the database when starting the app and displaying it. I have been able to get all the other information in the database to display, the only thing missing is the images when I open the app.
My code looks like this:
Sending the Image to the server
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
if (resultCode == Result.Ok)
{
int contactID = mContacts[(int)mSelectedPic.Tag].ID;
Stream stream = ContentResolver.OpenInputStream(data.Data);
mSelectedPic.SetImageBitmap(DecodeBitmapFromStream(data.Data, 150, 150));
Bitmap bitmap = BitmapFactory.DecodeStream (stream);
MemoryStream memStream = new MemoryStream ();
bitmap.Compress (Bitmap.CompressFormat.Webp, 100, memStream);
byte[] picData = memStream.ToArray ();
WebClient client = new WebClient ();
Uri uri = new Uri ("MYWESBITE/UpdateContact.php");
NameValueCollection parameters = new NameValueCollection ();
parameters.Add ("Image", Convert.ToBase64String(picData));
parameters.Add ("ContactID", contactID.ToString());
client.UploadValuesAsync (uri, parameters);
client.UploadValuesCompleted += Client_UploadValuesCompleted;
}
}
PHP code to handle the image and store it into the database as a VARBINARY
$imgData = base64_encode($mImage);
$sql = "UPDATE Contact SET ImageBase64 = '$imgData' WHERE ID = '$mContactID'";
$result = mysql_query($sql, $link);
if (!$result) {
echo "DB Error, could not query the database\n";
echo 'MySQL Error: ' . mysql_error();
exit;
}
Then when the app opens it calls this PHP function
$sql = "SELECT * FROM Contact";
$result = mysql_query($sql, $link);
if (!$result) {
echo "DB Error, could not query the database\n";
echo 'MySQL Error: ' . mysql_error();
exit;
}
//create an array
$contact_array = array();
while($row =mysql_fetch_assoc($result))
{
$contact_array[] = array("ID" => $row["ID"],
"Name" => $row["Name"],
"Number" => $row["Number"],
"ImageBase64" => base64_encode($row["ImageBase64"])
);
}
echo json_encode($contact_array);
This shows how I turn the base64_encoded string to a byte array
class Contact
{
public int ID { get; set; }
public string Name { get; set; }
public string Number { get; set; }
public string ImageBase64 { private get; set; }
public byte [] Image
{
get
{
if (ImageBase64 != "" && ImageBase64 != null)
{
byte[] image = Convert.FromBase64String (ImageBase64);
return image;
}
return null;
}
}
}
MainActivity.cs
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
mListView = FindViewById<ListView>(Resource.Id.listView);
mProgressBar = FindViewById<ProgressBar> (Resource.Id.progressBar);
mClient = new WebClient ();
mUrl = new Uri ("MYWEBSITE/GetContacts.php");
//Call the Client
mClient.DownloadDataAsync (mUrl);
mClient.DownloadDataCompleted += MClient_DownloadDataCompleted;
}
Then finally gets converted to image like this
ImageView pic = row.FindViewById<ImageView>(Resource.Id.imgPic);
if (mContacts[position].Image != null)
{
pic.SetImageBitmap(BitmapFactory.DecodeByteArray(mContacts[position].Image, 0, mContacts[position].Image.Length));
}
Thank you for your time everyone, I hope you can help me figure this out!
A few questions might help to answer this: At what point does it not work? Are you getting an error? or does the image not display?
Right off the bat, however, it looks like you are trying to interact from the UI from a background thread. Can you try wrapping the code in your MCClient_Downloaded method in RunOnUIThread?
I got it to work now. I changed my database type to be a Medium BLOB instead of a VARBINARY, and then got rid of the base64_encode() on the way into the database and then got rid of the base64_encode() on the way out of the database in the JSON creation.

xamarin android ListView with image

Im tring to load data from database and display on a ListView.
The list view contains 2 textview and 1 image view. Im using SQlite.net.
Where is my databse:
Database
public class contacts
{
[PrimaryKey, AutoIncrementAttribute, Column("id")]
public int id {get; set;}
public string name {get; set;}
public string number { get; set; }
public byte[] photo{ get; set; }
}
And where is my function to fill the listview:
private void refreshListView()
{
var db = new SQLiteConnection (MainActivity._DatabaseConnectString);
MatrixCursor mMatrixCursor = new MatrixCursor (new String[]{ "_id", "name", "number", "photo" });
SimpleCursorAdapter adap;
adap = new SimpleCursorAdapter (
this,
Resource.Layout.lv_layout,
null,
new String[]{ "name", "number", "photo" },
new int[]{ Resource.Id.tv_name, Resource.Id.tv_number, Resource.Id.iv_photo }, 0);
IEnumerable<contacts> table = db.Query<contacts> ("select * from contacts");
foreach (var contact in table) {
mMatrixCursor.AddRow (new Java.Lang.Object[] {contact.id,
contact.name, contact.number, BitmapFactory.DecodeByteArray (contact.photo, 0, contact.photo.Length)
});
}
lview.Adapter = adap;
adap.SwapCursor (mMatrixCursor);
}
The only problem is the image dont show and I have this error from the output:
[BitmapFactory] Unable to decode stream: java.io.FileNotFoundException: /android.graphics.Bitmap#42087da0: open failed: ENOENT (No such file or directory)
[System.out] resolveUri failed on bad bitmap uri: android.graphics.Bitmap#42087da0
I already done this application with java for android and I fix that problem with the this code but I dont know how to "translate" the code from java to c#.
Where is the java code below the adap:
adap.setViewBinder(new SimpleCursorAdapter.ViewBinder() {
#Override
public boolean setViewValue(View view, Cursor cursor, int i) {
if (view.getId() == R.id.iv_photo) {
byte[] Blobdata = cursor.getBlob(i);
Bitmap bitmap = Bitmap.createScaledBitmap(BitmapFactory.decodeByteArray(
Blobdata, 0, Blobdata.length), 150, 150, false);
((ImageView) view).setImageBitmap(bitmap);
return true;
} else {
return false;
}
}
});
Somebody can help me "translate" this code to c#? or use another code.
Thanks from the help and sorry my english.
EDITED 2
Ok where is the code translated to c#
class ViewBinder : Java.Lang.Object, SimpleCursorAdapter.IViewBinder
{
public bool SetViewValue (View view, Android.Database.ICursor cursor, int i)
{
if (view.Id == Resource.Id.iv_photo) {
byte[] Blobdata = cursor.GetBlob (i);
Bitmap bitmap = Bitmap.CreateScaledBitmap (BitmapFactory.DecodeByteArray (
Blobdata, 0, Blobdata.Length), 150, 150, false);
((ImageView)view).SetImageBitmap (bitmap);
return true;
} else {
return false;
}
}
}
But now I got an error in this line:
byte[] Blobdata = cursor.GetBlob (i);
Error:
android.graphics.Bitmap cannot be cast to byte[]
I think im getting this error becouse in my database im not using Blob but byte array. Somebody know how I can retrive byte array from database or how i can use Blob data type?
You can store a byte-array in a BLOB.
This is how I fetch it:
using (SqliteDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
images.Add(new Image((byte[])reader["Image"]));
}
}
I can then use my Image property ImageByteArray to convert it to a Bitmap, similar to the way you did.
Bitmap image = BitmapFactory.DecodeByteArray(data, 0, barray.Length);
The Bitmap is then ready to show in an ImageView.
imageView.SetImageBitmap(image);
As you can see, our methods are very much alike. So to me it seems cursor.GetBlob (i) returns something unexpected.
public abstract byte[] getBlob (int columnIndex)
Added in API level 1
Returns the value of the requested column as a byte array.
The result and whether this method throws an exception when the column value is null or the column type is not a blob type is implementation-defined.
Parameters:
columnIndex the zero-based index of the target column.
Returns:
the value of that column as a byte array.
(http://developer.android.com/reference/android/database/Cursor.html#getBlob(int))
According to the description from the method, it seems your column does not hold a BLOB/byte-array.
Use var Blobdata = cursor.GetBlob (i); to find out what is in it, and adjust accordingly.

Is DataGridView wrong choice?

I am new to C# and Windows Forms so please be patient. I am making a Windows Form that lets you load a video, load a script, then makes captions. I want to display a table where the data will be populated automatically as they mark starts and ends of caption and select text and will be editable. At the end I want to save all the data to an xml file. A DataGridView UI-wise seems like exactly what I want, but I can't figure out backend how to get the data out of the DataGridView ( preferably in a dataset).
I am now considering using a ListView with multiple columns instead. Any advice would be greatly appreciated
Datagridview should work just fine for that application and you can easily retrieve any data you save to it by doing:
dgvThing.DataSource;
That will contain whatever type that you have saved into the Datagridview (List, array, etc).
Example:
public class SuperFunObject {
public TimeSpan start { get; set; }
public TimeSpan end { get; set; }
public string selectedText { get; set; }
public SuperFunObject(Timespan a, Timespan b, string text) {
start = a;
end = b;
selectedText = text;
}
}
List<SuperFunObject> funList = new List<SuperFunObject>();
funList.Add(new SuperFunObject(TimeSpan.FromSeconds(0.0),TimeSpan.FromSeconds(20.0),"Hello"));
dgvThing.DataSource = funList;
...
...
//retrive your list
List<SuperFunObject> getData = ((List<SuperFunObject>)dgvThing.DataSource);
I hope the example helps a bit. Side note, the reason for the accessors (get,set) are for the Datagridview to be able to retrieve the data from the object for display.
Here is a little ditty that'll save a class that you populate into an array from your datasource to am XML file path that you specify in the parameter.
public static bool SaveXMLObjectToFile(object IncomingXMLObject, string Path)
{
string xmlString = null;
File TheFileIn = default(File);
string docname = null;
StreamWriter WriteAFile = default(StreamWriter);
string filelocation = null;
//Dim filelocation As String
System.IO.MemoryStream MemStream = new System.IO.MemoryStream();
System.Xml.Serialization.XmlSerializer Ser = default(System.Xml.Serialization.XmlSerializer);
System.Text.Encoding encodingvalue = System.Text.UTF8Encoding.UTF8;
System.Xml.XmlTextWriter writer = new System.Xml.XmlTextWriter(MemStream, encodingvalue);
bool Result = false;
try {
File.Delete(Path);
Ser = new System.Xml.Serialization.XmlSerializer(IncomingXMLObject.GetType);
Ser.Serialize(writer, IncomingXMLObject);
MemStream = writer.BaseStream;
//as system.io.memorystream
xmlString = UTF8ByteArrayToString(MemStream.ToArray());
//Will Not Convert Byte Array from Diagram
filelocation = Path;
WriteAFile = TheFileIn.AppendText(filelocation);
WriteAFile.Write(xmlString);
WriteAFile.Close();
Result = true;
} catch (Exception e) {
Result = false;
}
return Result;
}

trouble comparing strings in wp7 application

Here is a sample of my code.
Here I recieve a string variable from another page.
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedTo(e);
string newparameter = this.NavigationContext.QueryString["search"];
weareusingxml();
displayResults(newparameter);
}
private void displayResults(string search)
{
bool flag = false;
try
{
using (IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream stream = myIsolatedStorage.OpenFile("People.xml", FileMode.Open))
{
XmlSerializer serializer = new XmlSerializer(typeof(List<Person>));
List<Person> data = (List<Person>)serializer.Deserialize(stream);
List<Result> results = new List<Result>();
for (int i = 0; i < data.Count; i++)
{
string temp1 = data[i].name.ToUpper();
string temp2 = "*" + search.ToUpper() + "*";
if (temp1 == temp2)
{
results.Add(new Result() {name = data[i].name, gender = data[i].gender, pronouciation = data[i].pronouciation, definition = data[i].definition, audio = data[i].audio });
flag = true;
}
}
this.listBox.ItemsSource = results;
}
catch
{
textBlock1.Text = "error loading page";
}
if(!flag)
{
textBlock1.Text = "no matching results";
}
}
Nothing is loaded into the list when the code is run, I just get the message "no matching results".
Looks like you are trying to do a contains search (my guess based on your addition of the * around the search string. You can remove the '*' and do a string.Contains match.
Try this.
string temp1 = data[i].name.ToUpper();
string temp2 = search.ToUpper()
if (temp1.Contains(temp2))
{
It looks like you are trying to check if one string contains another (ie substring match) and not if they are equal.
In C#, you do this like this:
haystack = "Applejuice box";
needle = "juice";
if (haystack.Contains(needle))
{
// Match
}
Or, in your case (and skip the * you added to the string temp2)
if (temp1.Contains(temp2))
{
// add them to the list
}
Have you checked to make sure data.Count > 0?

How to cache images from a SQl Server 2005 database call?

I am having trouble using the output cache param in an aspnet 2.0 page directive. I am using a session variable to hold the value of the selected image. It seems that the dynamic control in a datalist, is not working when the output cache is set to true in the page directive. Is there a way to cache the images seperately to avoid using a page directive?
datalist code
" RepeatColumns="6" CellPadding="8" CellSpacing="8" GridLines="Both" SelectedItemStyle-BackColor="#33ff66" OnSelectedIndexChanged="dtlImages_SelectedIndexChanged" OnItemCommand="dtlImages_ItemCommand">
' Runat="server">
' ID="lblDescription" Font-Bold="True" Font-Size="12px" Font-Names="Arial">
code that retrieves the image from the database
protected void Page_Load(object sender, System.EventArgs e)
{
string strImageID = Request.QueryString["id"];
string wf4uConnect = System.Configuration.ConfigurationManager.ConnectionStrings["wf4uConnectionString"].ConnectionString;
System.Data.SqlClient.SqlConnection wf4uConn = new System.Data.SqlClient.SqlConnection(wf4uConnect);
System.Data.SqlClient.SqlCommand myCommand = new SqlCommand("Select ImageFile, ImageType from wf4u_ImageThumb Where ImageId =" + strImageID, wf4uConn);
wf4uConn.Open();
SqlDataReader byteReader = myCommand.ExecuteReader(CommandBehavior.CloseConnection);
while ((byteReader.Read()))
{
Response.BinaryWrite((byte [])byteReader.GetValue(0));
Response.ContentType = (string)byteReader.GetValue(1);
}
wf4uConn.Close();
}
I have implemented an http context object to cache the images as they're loaded into the webpage.
public ImageList (string clientName)
{
HttpContext context = HttpContext.Current;
if((context.Cache["ImageIdList" + clientName] == null))
{
string wf4uConnect = System.Configuration.ConfigurationManager.ConnectionStrings["wf4uConnectionString"].ConnectionString;
System.Data.SqlClient.SqlConnection wf4uConn = new System.Data.SqlClient.SqlConnection(wf4uConnect);
string queryStr = "SELECT ImageId FROM wf4u_imageThumb WHERE ClientName = #ClientName";
SqlCommand ImageIdComm = new System.Data.SqlClient.SqlCommand(queryStr, wf4uConn);
ImageIdComm.Parameters.Add("#ClientName", SqlDbType.VarChar).Value = clientName;
wf4uConn.Open();
SqlDataReader ImageIdReader = ImageIdComm.ExecuteReader();
if (ImageIdReader.Read())
{
_ImageId = ImageIdReader.GetInt32(0);
_ClientName = ImageIdReader.GetString(1);
context.Cache.Insert("ImageIdList" + clientName, this, null, DateTime.Now.AddSeconds(600), TimeSpan.Zero);
}
wf4uConn.Close();
}
else
{
ImageList list = (ImageList)context.Cache["ImageIdList" + clientName];
_ImageId = list.ImageId;
_ClientName = list.ClientName;
}
}
any suggestions would be welcomed.
You can use Cache object see: ASP.NET Caching: Techniques and Best Practices
You can implement an async handler like this:
using System;
using System.Web;
using System.Data.SqlClient;
public class FileHandler : IHttpAsyncHandler
{
#region Variables
private HttpContext _currentContext = null;
protected SqlCommand _command = null;
protected delegate void DoNothingDelegate();
#endregion
public void ProcessRequest(HttpContext context)
{
}
public void DoNothing()
{
}
public bool IsReusable
{
get { return false; }
}
#region IHttpAsyncHandler Members
public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
{
_currentContext = context;
int imageId;
if (int.TryParse(context.Request.QueryString["imageId"], out imageId))
{
// begin get file - make you own
// return FileController.BeginGetFile(out _command, cb, extraData, imageId);
}
else
{
DoNothingDelegate doNothingDelegate = new DoNothingDelegate(DoNothing);
return doNothingDelegate.BeginInvoke(cb, extraData);
}
}
public void EndProcessRequest(IAsyncResult result)
{
File file = null;
if (null != _command)
{
try
{
// end get file - make your own
// file = FileController.EndGetFile(_command, result);
}
catch { }
}
if (null != file)
{
// in my case File entity may be stored as a binary data
//or as an URL
// here is URL processing - redirect only
if (null == file.Data)
{
_currentContext.Response.Redirect(file.Path);
}
else
{
_currentContext.Response.ContentType = file.ContentType;
_currentContext.Response.BinaryWrite(file.Data);
_currentContext.Response.AddHeader("content-disposition", "filename=\"" + file.Name + (file.Name.Contains(file.Extension) ? string.Empty : file.Extension) + "\"" );
_currentContext.Response.AddHeader("content-length", (file.Data == null ? "0" : file.Data.Length.ToString()));
}
_currentContext.Response.Cache.SetCacheability(HttpCacheability.Private);
_currentContext.Response.Cache.SetExpires(DateTime.Now);
_currentContext.Response.Cache.SetSlidingExpiration(false);
_currentContext.Response.Cache.SetValidUntilExpires(false);
_currentContext.Response.Flush();
}
else
{
throw new HttpException(404, HttpContext.GetGlobalResourceObject("Image", "NotFound") as string);
}
}
#endregion
}
And set necessary values to the cache headers.
EDIT: Guess, in this case it would be better to use headers instead of using Cache object.
The way I do the images-from-the-database thing is to use a HTTP handler which reads the bits from the database, and sets the appropriate client-side caching headers in the response. I also support the If-Modified-Since header to suppress sending the blob if not required.
Then the page just has links to the handler with an image ID (must be careful to validate that the ID is an integer or whatever ID format you want to use - public sites get numerous SQL injection-style hack attempts.
For my current design the ID changes if the image is modified, so the caching time can be set to something long, e.g. a month or a year.

Categories

Resources