Saturday, February 17, 2007

How to Serialise Image

I was reading in the CodeProject C# forum when a question gave me the idea for a simple article.

The poster wanted to read an image into a byte array and had posted some sample code.

This is a concept that some time ago, I created several test projects when I wanted test the posibility of storing objects in a database.

I looked upon the image as being just another object and thought that a similar technique could be applied and set about creating a sample project.

I followed the same steps as detailed in my reply:


1) Create a new windows form app
2) Add to the form 2x picture boxes, one named source, the other dest
3) Add a new button named serialise
4) Set the background image of the picturebox named source to whatever you want
(for testing, do this using the designer)

5) Add a handler to the buttons click event

(this normally happens automatically if you double click the button in the designer)

6) Add using System.Runtime.Serialization.Formatters.Binary; declaration to your class
7) Paste the following code:
  void SerialiseClick(object sender, EventArgs e)
{
//serialise the background image of the source
byte[] byteArray = Serialise( source.BackgroundImage );
//deserialise the background image into the dest
dest.BackgroundImage = (System.Drawing.Image)Deserialise(byteArray);
}

public static byte[] Serialise( object obj )
{
//instanciate a new memory stream
System.IO.MemoryStream ms = new System.IO.MemoryStream();
//instanciate a new BinaryFormatter
BinaryFormatter bf = new BinaryFormatter();
//serialise the object into the memory stream
bf.Serialize( ms, obj );
//return the memory stream as a byte array
return ms.ToArray();
}

public static object Deserialise( byte[] obj )
{
//read the object into a memory stream
System.IO.MemoryStream ms = new System.IO.MemoryStream( obj );
//instanciate a binary formatter
BinaryFormatter bf = new BinaryFormatter();
//return the deserialised byte array as an object
return bf.Deserialize(ms) ;
}
With any luck, when the application is run, the resulting form should look similar to the one as pictured bellow:



If the code was pasted correctly, clicking the 'Serialise' button should invove the buttons click method where:
  • the background of the source image is serialised into a byte array
  • the byte array is de-serialised into an image
  • the image is set as the background of the destination image
This should result in the image being displayed in the 'Serialised Image' picture box which would therfor look as follows:



The sample project can be downloaded from here: http://www.box.net/public/14kiat6na7

The original post can be viewed here: CodeProject C# Forum

Thursday, August 24, 2006

Reading and writing a BLOB from Firebird

I'ts been a long time since I've written anything so I thought I'd make it usefull.

For those of you who don't know, a BLOB is a Binary Large Object and is a data type for storing binary (and text) data in a database.

It could be used for storing images, files etc in a database for later retrieval or even to persist objects.

There are scarce resources on the Internet relating to this subject in relation to the Firebird database. Whilst researching this topic, many of the links I found led me back to the following page:

http://www.dotnetfirebird.org/blob-reading-example-csharp

I'ts a great site and many people link to it, however you would be mislead to think that this was the only method.


The code which follows assumes that a database table named BLOB_DATA already exists and contains the columns ID and DATA, a similar table could be ctreated by executing the following script:

--==============================================================
-- Create Tables
--==============================================================
CREATE TABLE BLOB_DATA (
ID INTEGER NOT NULL,
DATA BLOB NOT NULL,
PRIMARY KEY (ID) );

--==============================================================
-- Create Generators for Auto Increment Primary Keys
--==============================================================
CREATE GENERATOR GEN_BLOB_DATA;

--==============================================================
-- Create Triggers for Auto Increment Primary Keys
--==============================================================
SET TERM ^ ;
CREATE TRIGGER ID FOR BLOB_DATA
ACTIVE BEFORE INSERT
AS
BEGIN
IF(NEW.ID IS NULL) THEN
NEW.ID = GEN_ID(GEN_BLOB_DATA, 1);
END^
SET TERM ; ^

The following code will store a BLOB from a Firebird database:

public void SaveBlob( byte[] data )
{
//instanciate a new connection string builder
FbConnectionStringBuilder csb = new FbConnectionStringBuilder();
csb.Database = "MyDatabase";
csb.UserID = "SYSDBA";
csb.Password = "masterkey";
csb.ServerType = 1; //embedded server

//instanciate a connection object
FbConnection con = new FbConnection(csb.ToString());

//build the query
cmd = new FbCommand( "INSERT INTO BLOB_DATA VALUES ( null, @data )", con );
//add the parameters
cmd.Parameters.Add( "@data", data );
//open the connectoin
con.Open();
//execute the query
cmd.ExecuteNonQuery();
//close the connection
con.Close();
}



The following code will read BLOB data from a Firebird dataase:

public byte[] ReadBlob( int id )
{
//instanciate a new connection string builder
FbConnectionStringBuilder csb = new FbConnectionStringBuilder();
csb.Database = "MyDatabase";
csb.UserID = "SYSDBA";
csb.Password = "masterkey";
csb.ServerType = 1; //embedded server

//instanciate a connection object
FbConnection con = new FbConnection(csb.ToString());

//build the query
cmd = new FbCommand( "SELECT * FROM BLOB_DATA WHERE ID = @id", con );
//add the parameters
cmd.Parameters.Add( "@id", id );
//open the connectoin
con.Open();
//execute the query
FbDataReader reader = cmd.ExecuteReader();

byte[] data = null;
//read the data
while ( reader.Read() )
{
data = (byte[])reader["DATA"] ;
}
//close the connection
con.Close();

return data;
}

In the real world, you wouldn't instanciate a new connection string in each method, the database routines would possibly be static methods inside a sealed class. This was just a quick'n'dirty demonstration of a simple method to achieve the required results.

Saturday, February 18, 2006

PING can hurt!


Who would have thought that a simple PING command could ever cause any problems?

There have been many occasions when I've tested network connections using this simple command and even used a Ping utility like Angry IP Scanner to see what IP addresses were active.

Well, you can only imaging my surprise when all hell broke loose whilst investigating a problem with an Epson TM-U220 Printer fitted with an Ethernet Interface.

We had several printers connected to an isolated network that had been setup for a demonstration. One of the printers (not an Epson) had stopped working and I was asked to investigate. None of the original configuration had changed since the earlier demo where it was left in a working condition.

I used the Ping utility to test for responding equipment and observed the Epson TM-U220 print a configuration ticket that showed the IP address had changed. This only occurred occasionally.

Eventually, I discovered that this only happened when the Ping utility was set to scan all the IP addresses on the subnet including the broadcast IP (EG 192.168.1.255).

At first I thought that there could be a fault with the utility that caused this strange problem with the printer. To test this theory, I performed a PING from the command prompt that fortunately had the same affect and caused the printer to print another configuration ticket.

The first problem was that each time the printer was reconfigured, it was set to use the broadcast address. The implication of this is that, every machine on the same subnet hears any message sent to the broadcast IP. Imagine sending a print request to the broadcast IP and having all the printers print the same message!

The second problem is that, once set to the broadcast address, the normal programming utilities would not work, they couldn’t connect to the broadcast address.

I realised that we had to connect using the hardware (MAC) address but hadn’t done this before. As we were running out of time, I prepared two other replacement printers. This left me with the challenge of fixing the problem printers in my spare time.

With some help from a colleague, we eventually discovered that we could get the printer back to its correct IP address using a combination of ARP (Address Resolution Protocol) and PING commands.

This is how:

Make a note of the printers Ethernet Address, this was printed on the configuration ticket. You can often force the printer to print this information by pressing the reset button near the RJ45 socket of the network card. There may also be a label by the port stating this address.
Once you known the Ethernet address of the printer, simply use the ARP command as follows:

arp -s 192.168.0.173 00-20-7F-CB-37-77

This command tells the printer that has a Ethernet address of 00-20-7F-CB-37-77 to change its IP address to 192.168.0.173.

To actually change the IP address of the printer, use the PING command to send the ARP information just specified as follows:

PING 192.168.0.173

The above procedure would add an entry to the ARP table on the PC from which the command was performed. This can be deleted as follows:

arp -d 192.168.0.173

The printer should now have the required IP address and should connect to the configuration software should any further changes be required.


I am sure that this problem is not specific to the Epson printer however, this is my first experience of what could have been a major problem.

It is also worth noting that the configuration software also has an option to disable programming by PING although I do not know the implications of disabling this.

In my search for a solution, I found the following references useful:


I hope this saves someone the torment we suffered.

Wednesday, November 02, 2005

Run an embedded SQL Script against Firebird

I had an idea that it would be great if my application could automatically create any database that it required.

I have in the past attempted to hardcode database construction routines but dislike this approach as it makes the code messy and difficult to maintain. Instead, I favoured the idea of executing a script containing my SQL statements which could be used to construct the database. The application would just simply execute the script, an approach I’ve used in the past with SQL Sever.

Whilst investigating further, I found these useful links:

Using FbConnectionStringBuilder
Batch SQL/DDL Execution

However, distributing a separate script file would allow a user to change or view the contents of the file.

Having experimented with embedded resource files, I thought a similar approach would protect the script from abuse by the average user and only venerable to experienced programmers.

I tested various routines and arrived at the following working example:

void ButtonRunScriptClick(object sender, System.EventArgs e)
{
//specify the database name
string dbName = "test.fdb";
//instanciate a new connection stringbuilder
FbConnectionStringBuilder csb = new FbConnectionStringBuilder();
csb.Database = dbName;
csb.UserID = "SYSDBA";
csb.Password = "masterkey";
csb.ServerType = 1;         //embedded server
//instanciate a connection object
FbConnection con = new FbConnection(csb.ToString());
//check if the database exists
if (System.IO.File.Exists(dbName) == false)
//create the database as it didn’t exist
FbConnection.CreateDatabase(csb.ToString());
//run the script against the current connection
RunScript("Test.Sql", con);
}

void RunScript(string ScriptName, FbConnection connection)
{
//get a reference to the executing assembly
System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly();
//instanciate a textReader object initialised using a stream to the embedded resource
System.IO.TextReader textReader = new System.IO.StreamReader(assembly.GetManifestResourceStream(ScriptName));
FbScript script = new FbScript(textReader);
//parse the script
script.Parse();
//open the connection
connection.Open();
FbBatchExecution fbe = new FbBatchExecution(connection);
foreach (string cmd in script.Results)
{
//add each sql statement to the batch
fbe.SqlStatements.Add(cmd);
}
//execute the batch
fbe.Execute();
//close the connection
connection.Close();
}

To test the above code, you will need to do the following:
1)     Download and install the 'Firebird ADO.Net Provider' from DotNetFirebird
2)     Once installed, create a new Windows Application and add a reference to your project for the FirebirdSql.Data.Firebird assebly loaded in the GAC.
3)     Copy & Paste the sample code into your project.
4)     Add the following Using Directives:

using FirebirdSql.Data.Firebird;
using FirebirdSql.Data.Firebird.Isql;

5)     Download 'Embedded Firebird for Windows' from DotNetFirebird and extract ‘fbembed.dll’ and ‘firebird.msg’ from the zip archive. These files should be copied to your applications directory.
6)     Create a text file named 'Test.Sql' to contain your Firebird SQL script and save it in your project directory. I would suggest including a CREATE TABLE statement such as:

CREATE TABLE CLIENTS (
client_id integer not null,
firstname char(20),
lastname char(20),
PRIMARY KEY (client_id));

Note: The filename is case sensitive, if you choose a different filename you will need to amend the sample code to reflect this change.

7)     Add the file you created in Step 4 to your project and set the build action to Embedded Resource.
8)     Add a button to your form named buttonRunScript and check that its Click Event is set to the ButtonRunScriptClick Event Handler.

Hopefully, when you build the project and click the Run Script button, a file will be created in the applications directory named ‘TEST.FDB’.

Providing there were no errors during the applications execution the database should have been constructed according to the statements in the SQL script.

There are several Database Admin Tools you can use to inspect/update and alter the database, one of which is FlameRobin which can also be downloaded for free.    

Tuesday, November 01, 2005

C# Programming using SharpDevelop

SharpDevelop is a great IDE for developing C# applications. Best of all, its free.

Yes, thats right, free and can be downloaded from www.icsharpcode.net

Don't get me wrong, I once loved Visual Studio. Not only is it a great IDE but it gave me loads of ideas. What I now hate about the product is that its written by Microsoft.

My main reason for my dislike was because I have purchased several Microsoft products:

Visual C++ v6 Deluxe Learning Edidtion (DLE)
Visual Studio .Net v2000

When I purchased VS C++ DLE, after writting several sample applications, I was disapointed to find the license did not allow me to distribute any application made with the package.

Several years on, I purchased VS.Net 2000 when I started a distance learning course. When VS.2002 was released, Microsoft offered an upgrade for a small fee (approx £19). I was annoyed to discover that because the version I had purchased was "An Accademic Version", the upgrade offer was not applicable.

Having never distributed any application, I could not warrant spending £700-800 on the new version. I scoured the Google in anger for Open Source C# IDE and found SharpDevelop.

I must admit, its not perfect, but neither is Visual Studio. But because of my past experiences, I'm doing what I can to stop using Microsoft Products and support others to develop alternatives.

I no longer use Internet Explorer, instead I use Firefox.
I dont use SQL Server, instead I've used MySQLServer or Firebird.
I dont use Visual Studio, instead I used SharpDevelop

What would you do?

Monday, October 31, 2005

Adventures into the world of C#

I'm yet again of on another journey of exploration. I think it's this constant learning curve that makes programming so interesting.

This time i'm investigating usung Firefox as the back-end of a C# application.

I've started using the embedded version as it can be easily distributed and installed.