Sooner or later, you will find the need of handling image in your code, especially when you're working with a database. So in this article, I share with you some useful methods that I find myself using frequently. They include: saving image in a folder, getting thumbnail from the original image, converting image to binary for saving in database, and converting binary data back to image.
Save An Image
Image originalImage = Image.FromFile(imagePath);
string filePath = AppDomain.CurrentDomain.BaseDirectory + savedName;
originalImage.Save(filePath, System.Drawing.Imaging.ImageFormat.Jpeg);This code saves the image to the base directory of your app or website.
imagePath is the full path to the image that we need to save (e.g. "C:\Pictures\Lighthouse.jpg"), one way to get this is use an OpenFileDialog.
savedName is the name for the saved image.
Save the Image as a Thumbnail
public static void SaveImage(string imagePath, string savedName,
int width = 0, int height = 0)
{
Image originalImage = Image.FromFile(imagePath);
string filePath = AppDomain.CurrentDomain.BaseDirectory + savedName;
if (width > 0 && height > 0)
{
Image.GetThumbnailImageAbort myCallback =
new Image.GetThumbnailImageAbort(ThumbnailCallback);
Image imageToSave = originalImage.GetThumbnailImage
(width, height, myCallback, IntPtr.Zero);
imageToSave.Save(filePath, System.Drawing.Imaging.ImageFormat.Jpeg);
}
else
{
originalImage.Save(filePath, System.Drawing.Imaging.ImageFormat.Jpeg);
}
}
private static bool ThumbnailCallback() { return false; }Note the parameters: int width = 0 & int height = 0. This is a C# 4.0 feature: Optional Parameters, so we can call this method like this: (assume this method is in the ImageHandling class).
// Save image as original
ImageHandling.SaveImage(@"C:\Pictures\Lighthouse.jpg", "OriginalLighthouse.jpg");
// Save image as thumbnail
ImageHandling.SaveImage(@"C:\Pictures\Lighthouse.jpg",
"ThumbnailLighthouse1.jpg", 160, 90);
// New feature: Named Parameter
ImageHandling.SaveImage(@"C:\Pictures\Lighthouse.jpg",
"ThumbnailLighthouse2.jpg", height: 90, width: 160);Resize the Image and Keep Aspect Ratio
int newWidth = originalImage.Width * percentage / 100;
int newHeight = originalImage.Height * percentage / 100;To keep the image aspect ratio, simply replace width & height parameters with percentage parameter and call the GetThumbnailImage method with our new width & height.
Convert Image to Binary
public static byte[] ImageToBinary(string imagePath)
{
FileStream fileStream = new FileStream(imagePath, FileMode.Open, FileAccess.Read);
byte[] buffer = new byte[fileStream.Length];
fileStream.Read(buffer, 0, (int)fileStream.Length);
fileStream.Close();
return buffer;
}Use this method when you want to save images in your database. The column to store binary data is usually varbinary(MAX).
Convert Binary to Image
You store images in your database as binary, of course you must convert binary back to images so you can display them in your app.
public static Image BinaryToImage(System.Data.Linq.Binary binaryData)
{
if (binaryData == null) return null;
byte[] buffer = binaryData.ToArray();
MemoryStream memStream = new MemoryStream();
memStream.Write(buffer, 0, buffer.Length);
return Image.FromStream(memStream);
}You may need to add reference to System.Data.Linq. LINQ-to-SQL maps a varbinary column in your database to its relevant property as System.Data.Linq.Binary.
Monday, May 30, 2011
Sunday, May 29, 2011
Using Speech class in .net
Overview
Introduction
The Speech API library that we are going to use today is represented by the file sapi.dll which’s located in %windir%\System32\Speech\Common. This library is not part of the .NET BCL and it’s not even a .NET library, so we’ll use Interoperability to communicate with it (don’t worry, using Visual Studio it’s just a matter of adding a reference to the application.)
Implementation
In this example, we are going to create a Console application that reads text from the user and speaks it. To complete this example, follow these steps:
As an example, we’ll create a simple application that reads user inputs and speaks it. Follow these steps:
1.Create a new Console application.
2.Add a reference to the Microsoft Speech Object Library
3.Write the following code and run your application:
01.// C#
02.using SpeechLib;
03.static void Main()
04.{
05. Console.WriteLine("Enter the text to read:");
06. string txt = Console.ReadLine();
07. Speak(txt);
08.}
09.static void Speak(string text)
10.{
11. SpVoice voice = new SpVoiceClass();
12. voice.Speak(text, SpeechVoiceSpeakFlags.SVSFDefault);
13.}
01.' VB.NET
02.Imports SpeechLib
03.Sub Main()
04. Console.WriteLine("Enter the text to read:")
05. Dim txt As String = Console.ReadLine()
06. Speak(txt)
07.End Sub
08.Sub Speak(ByVal text As String)
09. Dim voice As New SpVoiceClass()
10. voice.Speak(text, SpeechVoiceSpeakFlags.SVSFDefault)
11.End Sub
If you are using Visual Studio 2010 and .NET 4.0 and the application failed to run because of Interop problems, try disabling Interop Type Embedding feature from the properties on the reference SpeechLib.dll.
Building Talking Strings
Next, we’ll make small modifications to the code above to provide an easy way to speak a given System.String. We’ll make use of the Extension Methods feature of LINQ to add the Speak() method created earlier to the System.String. Try the following code:
01.// C#
02.using SpeechLib;
03.static void Main()
04.{
05. Console.WriteLine("Enter the text to read:");
06. string txt = Console.ReadLine();
07. txt.Speak();
08.}
09.static void Speak(this string text)
10.{
11. SpVoice voice = new SpVoiceClass();
12. voice.Speak(text, SpeechVoiceSpeakFlags.SVSFDefault);
13.}
01.' VB.NET
02.Imports SpeechLib
03.Imports System.Runtime.CompilerServices
04.Sub Main()
05. Console.WriteLine("Enter the text to read:")
06. Dim txt As String = Console.ReadLine()
07. txt.Speak()
08.End Sub
09. _
10.Sub Speak(ByVal text As String)
11. Dim voice As New SpVoiceClass()
12. voice.Speak(text, SpeechVoiceSpeakFlags.SVSFDefault)
13.End Sub
I Love YOU ♥
Let’s make it more interesting. We are going to code a VBScript file that says “I Love YOU” when you call it. To complete this example, these steps:
1.Open Notepad.
2.Write the following code:
1.CreateObject("SAPI.SpVoice").Speak "I love YOU!"
Of course, CreateObject() is used to create a new instance of an object resides in a given library. SAPI is the name of the Speech API library stored in Windows Registry. SpVoice is the class name.
3.Save the file as ‘love.vbs’ (you can use any name you like, just preserve the vbs extension.)
4.Now open the file and listen, who is telling that he loves you!
Microsoft Speech API has many voices; two of them are Microsoft Sam (male), the default for Windows XP and Windows 2000, and Microsoft Ann (female), the default for Windows Vista and Windows 7.
Introduction
The Speech API library that we are going to use today is represented by the file sapi.dll which’s located in %windir%\System32\Speech\Common. This library is not part of the .NET BCL and it’s not even a .NET library, so we’ll use Interoperability to communicate with it (don’t worry, using Visual Studio it’s just a matter of adding a reference to the application.)
Implementation
In this example, we are going to create a Console application that reads text from the user and speaks it. To complete this example, follow these steps:
As an example, we’ll create a simple application that reads user inputs and speaks it. Follow these steps:
1.Create a new Console application.
2.Add a reference to the Microsoft Speech Object Library
3.Write the following code and run your application:
01.// C#
02.using SpeechLib;
03.static void Main()
04.{
05. Console.WriteLine("Enter the text to read:");
06. string txt = Console.ReadLine();
07. Speak(txt);
08.}
09.static void Speak(string text)
10.{
11. SpVoice voice = new SpVoiceClass();
12. voice.Speak(text, SpeechVoiceSpeakFlags.SVSFDefault);
13.}
01.' VB.NET
02.Imports SpeechLib
03.Sub Main()
04. Console.WriteLine("Enter the text to read:")
05. Dim txt As String = Console.ReadLine()
06. Speak(txt)
07.End Sub
08.Sub Speak(ByVal text As String)
09. Dim voice As New SpVoiceClass()
10. voice.Speak(text, SpeechVoiceSpeakFlags.SVSFDefault)
11.End Sub
If you are using Visual Studio 2010 and .NET 4.0 and the application failed to run because of Interop problems, try disabling Interop Type Embedding feature from the properties on the reference SpeechLib.dll.
Building Talking Strings
Next, we’ll make small modifications to the code above to provide an easy way to speak a given System.String. We’ll make use of the Extension Methods feature of LINQ to add the Speak() method created earlier to the System.String. Try the following code:
01.// C#
02.using SpeechLib;
03.static void Main()
04.{
05. Console.WriteLine("Enter the text to read:");
06. string txt = Console.ReadLine();
07. txt.Speak();
08.}
09.static void Speak(this string text)
10.{
11. SpVoice voice = new SpVoiceClass();
12. voice.Speak(text, SpeechVoiceSpeakFlags.SVSFDefault);
13.}
01.' VB.NET
02.Imports SpeechLib
03.Imports System.Runtime.CompilerServices
04.Sub Main()
05. Console.WriteLine("Enter the text to read:")
06. Dim txt As String = Console.ReadLine()
07. txt.Speak()
08.End Sub
09.
10.Sub Speak(ByVal text As String)
11. Dim voice As New SpVoiceClass()
12. voice.Speak(text, SpeechVoiceSpeakFlags.SVSFDefault)
13.End Sub
I Love YOU ♥
Let’s make it more interesting. We are going to code a VBScript file that says “I Love YOU” when you call it. To complete this example, these steps:
1.Open Notepad.
2.Write the following code:
1.CreateObject("SAPI.SpVoice").Speak "I love YOU!"
Of course, CreateObject() is used to create a new instance of an object resides in a given library. SAPI is the name of the Speech API library stored in Windows Registry. SpVoice is the class name.
3.Save the file as ‘love.vbs’ (you can use any name you like, just preserve the vbs extension.)
4.Now open the file and listen, who is telling that he loves you!
Microsoft Speech API has many voices; two of them are Microsoft Sam (male), the default for Windows XP and Windows 2000, and Microsoft Ann (female), the default for Windows Vista and Windows 7.
Generating email address images
Nowadays, you can't publish an email address anywhere without receiving a bunch of spam immediately after. Those spam web crawlers just search in every site looking for everything and anything that resembles an email address.
I very often see people use different variations of writing their email like "myname at mydomain.com" or "myname at mydomain dot com".
I don't think this covers it anymore...
The best way, in my opinion, is to create an image of the email address instead of writing it. (That's what Facebook does as well.)
I started working on a user based site, and the users' emails will be displayed throughout the site. So I created a class that will dynamically generate email address images for me so my precious users won't be so vulnerable to all the spam out there.
Here it is:
// Members //
private int _emailFontSize = 8;
private string _emailFontFamily = "Verdana";
private Brush _emailBackgroundColor = Brushes.White;
private Brush _emailFontColor = Brushes.Navy;
// Properties //
// I cut this out, just for convenience //
// Methods //
public void CreateEmailImage(string email)
{
// create the font object
Font myFont = new Font(_emailFontFamily, _emailFontSize);
// create the image object
Bitmap emailImage = new Bitmap((int)(myFont.SizeInPoints * email.Length),
myFont.Height);
Graphics imgGraphics = Graphics.FromImage((Image)emailImage);
imgGraphics.FillRectangle(_emailBackgroundColor,
new Rectangle(new Point(0, 0), emailImage.Size));
imgGraphics.DrawString(email, myFont, _emailFontColor, new PointF(0, 0));
// measure the actual size of the email string
SizeF stringSize = imgGraphics.MeasureString(email, myFont);
// crop the image we created
Bitmap finalImage = CropImage(emailImage,
new Rectangle(new Point(0, 0), new Size((int)stringSize.Width,
(int)stringSize.Height)));
// save the image to a local file
finalImage.Save(email + ".gif", ImageFormat.Gif);
}
private Bitmap CropImage(Image imgCrop, Rectangle cropArea)
{
Bitmap bmpImage = new Bitmap(cropArea.Width, cropArea.Height - 1);
Graphics bmpG = Graphics.FromImage(bmpImage);
bmpG.DrawImage(imgCrop, new Point(0, 0));
return bmpImage;
}
}
I very often see people use different variations of writing their email like "myname at mydomain.com" or "myname at mydomain dot com".
I don't think this covers it anymore...
The best way, in my opinion, is to create an image of the email address instead of writing it. (That's what Facebook does as well.)
I started working on a user based site, and the users' emails will be displayed throughout the site. So I created a class that will dynamically generate email address images for me so my precious users won't be so vulnerable to all the spam out there.
Here it is:
// Members //
private int _emailFontSize = 8;
private string _emailFontFamily = "Verdana";
private Brush _emailBackgroundColor = Brushes.White;
private Brush _emailFontColor = Brushes.Navy;
// Properties //
// I cut this out, just for convenience //
// Methods //
public void CreateEmailImage(string email)
{
// create the font object
Font myFont = new Font(_emailFontFamily, _emailFontSize);
// create the image object
Bitmap emailImage = new Bitmap((int)(myFont.SizeInPoints * email.Length),
myFont.Height);
Graphics imgGraphics = Graphics.FromImage((Image)emailImage);
imgGraphics.FillRectangle(_emailBackgroundColor,
new Rectangle(new Point(0, 0), emailImage.Size));
imgGraphics.DrawString(email, myFont, _emailFontColor, new PointF(0, 0));
// measure the actual size of the email string
SizeF stringSize = imgGraphics.MeasureString(email, myFont);
// crop the image we created
Bitmap finalImage = CropImage(emailImage,
new Rectangle(new Point(0, 0), new Size((int)stringSize.Width,
(int)stringSize.Height)));
// save the image to a local file
finalImage.Save(email + ".gif", ImageFormat.Gif);
}
private Bitmap CropImage(Image imgCrop, Rectangle cropArea)
{
Bitmap bmpImage = new Bitmap(cropArea.Width, cropArea.Height - 1);
Graphics bmpG = Graphics.FromImage(bmpImage);
bmpG.DrawImage(imgCrop, new Point(0, 0));
return bmpImage;
}
}
10 things to make your desktop database apps better
Data driven applications rely on their databases
Everyone knows that any app driven by data is much more than just the app. In most cases the app without a database doesn’t even function, or fails to function properly. If a database is an integral part of your application, then shouldn’t you be doing all you can to ensure it stays healthy and prepare for the worst case events of corruption or dead drives?
This week we have been contacted by 5 long time users who suddenly lost or corrupted their data. Two of these were end user data that is going to cost a huge amount of labor to reproduce. In all of these cases the following simple procedures would have prevented the situation entirely.
1 – Backup your databases
This seems pretty obvious, right? The database is just a file, xcopy it and make a backup. Enforce backups within your app, make it an integral part of the application. If a user accidentally deletes a huge part of their data, how can you recover it? With a backup it is pretty easy.
Example Strategy
When your app starts up make a backup of the database in a subfolder. A simple name of \backups within your application directory. If you want to get fancy you could even create a subdirectory under that for the YYYY-MM, or when you backup the database rename it DatabaseName-YYYY-MM.vdb4. Then you can easily show the user backups in the directory and let them pick one to restore.
To prevent the backups from growing without bounds, you can periodically sum up the sizes of them all and delete the oldest ones until you are under some threshold for size. I can almost guarantee you that having 100MB of disk space for backups is no big deal to most users these days. If that gives them a month of backups they will thank you immensely should something bad happen in the future.
2 – Ensure clean shutdown detection in single user apps
Have you ever had Microsoft Outlook crash on you while running? What happens when it restarts? Outlook will revalidate the PST file to ensure it is not corrupt.
Every app that has a database connection open should have some way to detect if it was shutdown clean. It is the only way you will know that the application was terminated (either by the user, a crash, or the OS).
Remember that VistaDB lives WITHIN your application. So when your app dies, so does the engine. A server system doesn’t have to worry about this issue because the server service is still the only thing ever talking to the file.
Example Strategy
I typically include at startup a check for a registry key. If the key still exists at startup then the app is either still running locally, or it was not shutdown clean during the last run. I put the clear function for the registry key as the very last thing that happens before the application exits. Not when I want to exit (you could still crash trying to shutdown cleanly), but right before the actual exit.
In a C# program you can do this in the Program Main function. Always put a try / catch block around the main running of your application, then add a finally that clears the shutdown.
If you want a great tool to help catch other application errors and report them I suggest Gibraltar Software. They have made it very easy to integrate a general purpose catch error system into almost any app.
3 – Ensure clean shutdown detection in multi user apps
Multi user apps are a little harder to track because you may not be the only one in the database at the time an app fails or is terminated (or the OS crashes, etc). You should still follow the above for detecting your actual application shutting down correctly, but you now have to add some more complex logic around the packing / cleanup case.
Example Strategy
We have deployed a fairly simple strategy by adding a System_Settings table on some projects. This settings table would include only 1 row normally, but include information about the last time a backup was made (to prevent every app from trying to backup when they startup), and whether the database had a dirty shutdown. When the dirty flag is set (from shared mode) the application then tries to open the database exclusive to pack. Depending upon your application you could be checking for this periodically within your app from other desktops and if the flag is seen release all connections for some period of time and then start trying to access the database again.
There are lots of different ways you could do this depending upon your application design. You could also put a flat file next to the database dirty.txt that every connection class checks before opening the database, etc. The important thing is to make sure that dirty shutdowns are detected and can be recovered without user intervention.
4 – Handle exceptions in your code
See the Gibraltar Software page for software to help you do this everywhere in your code. But even if you don’t use something like their software, you still need to ensure everywhere something can go wrong you handle it.
What if you run out of disk space during an insert? What if updating a row throws a concurrency exception? Ensure you handle those cases.
Example Strategy
The easiest way to do this is to encapsulate your database functions into a Data Access Layer (DAL). It does not have to be a separate assembly outside your application. Just ensure that you have a uniform way of accessing the database and can trap all errors. Log them to ensure that errors you didn’t expect can easily be reported back to you, even if the user has to go find a flat file called “Errors.txt” in the directory and email it to you, that is better than nothing.
5 – Put all objects in using() statements
So many of the Microsoft examples should show this best practice, but don’t. I personally don’t think it adds anything to the readability of the sample, and it is a best practice. So it should be shown at all times.
Basically anytime you are allocating an object that has a disposing on it you should be putting it into a using() block. This ensures that the GC is going to clean it up as fast as possible. Calling .Close() on the object and setting it to nothing or null is NOT the same thing. You have to call .Close(), .Dispose() and then make sure all references are gone.
Example Strategy
using (VistaDB.Provider.VistaDBDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
// Do something
}
}This one thing will do more to reduce your memory problems, fix phantom errors that occur, and so much more. I have fixed so many customer problems by simply adding using() around their object allocations. VistaDB is 100% managed code, if you don’t clean us up, or hold references to us, the objects can be pinned in RAM a very long time.
6 – Use transactions only when required
Transactions are expensive, very expensive for a file based database. Don’t use them to update a single entry in a single table, or create a transaction just to run a select query. Only use them when they make sense.
Also read the Transactions can hurt performance on our blog.
7 - Encrypt only when required, do not use for password control
This one comes into play quite often from former Access programmers. Access had this concept of a password for control of opening the file by the end user in their own copy of Access. There is no need for such a concept with VistaDB. In VistaDB 4 we changed the name from password to Encryption Phrase to make it clearer that the password is being used for encryption.
Encryption takes that base phrase, adds a salt to it, and then every page is encrypted at write time, and decrypted at load time. This is quite expensive (30% or more overhead), and if your database becomes corrupt we have no way to recover encrypted data (would sort of defeat the purpose of encryption).
You can turn on encryption for the database, and then turn it off for certain tables if you only need a single table encrypted. But this still leaves all the headers on disk encrypted, and cannot be recovered.
8 – Debug with a clean copy
Don’t debug against a production database (ever!). Especially running tests like NUnit you always want to start with a known state. The easiest way to do this is to put a pre-populated database in the application directory, and set the option in Visual Studio to Copy it to the output directory always. That way at each build you have a clean database in your debugging directory.
This is probably the #1 way people corrupt their databases. Stopping and killing the engine while doing lots of activity is eventually going to cause a corruption. Try to take SQL Server and kill it every time you stop debugging, I guarantee that you will end up with a bad database after enough iterations.
9 – Ensure regular maintenance of databases
Create a regular maintenance cycle within your app. The app could do this weekly, monthly, or based upon some internal defined “usage” case. If you know each run of your app can generate 10% turn over of data, then you should pack every 10 runs to keep the database at it’s smallest size and optimal format.
Example Strategy
Add a SYSTEM_MAINTENANCE table to your database that only has one row. LASTPACKED DateTime. Just that one field will help you determine when the database was last cleaned up. You could allow the user to do it, or prompt them, or do it in the background if you know you are at a low point for user activity.
The import thing is to have a regular plan for maintaining the database. SQL Server has these maintenance plans built in to perform index rebuilds, etc at periodic intervals. We don’t have that ability because we are only running when you are running, and we never know how long that run will last.
10 – Prepare for regular updates to components
Have a way to deploy updates to your users. You will eventually run into a bug that all your users need to avoid, or updated components from a vendor (like us). If you have no way to get that update out, you are going to have some unhappy users.
VistaDB updates periodically, and I am sure your other vendors do as well. We don’t put out updates for no reason. There are almost always fixes and updates in every build. You don’t have to rush to deploy a new major or minor, but builds within your major.minor should be considered required maintenance updates.
Sometimes customers contact us with problems from VistaDB 3.0 builds that they have never updated. Sorry, we publish regular updates, put them on the site, list them in RSS feeds, blog posts, etc. There are plenty of ways to see and get the updates. If you are running VistaDB 3.5 and are still using the initial builds you are doing yourself a disservice by not getting the more recent builds.
Any vendor product you are using that has not been updated in 12+ months is either dead (no new development), obsolete, or very trivial in nature.
Example Strategy
Pick a date (Microsoft uses the first Tuesday of the month) to go visit all your vendors. See if they have updates, read through the release notes. Plan to integrate and test them with your next build. If any of the updates from vendors are critical, then you have a critical update to perform as well.
Make sure you have a way to get updates to users. You don’t have to write all this yourself, Tarma Installer provides a very simple way to get web updates into your applications without writing complicated setup and download scripts.
Everyone knows that any app driven by data is much more than just the app. In most cases the app without a database doesn’t even function, or fails to function properly. If a database is an integral part of your application, then shouldn’t you be doing all you can to ensure it stays healthy and prepare for the worst case events of corruption or dead drives?
This week we have been contacted by 5 long time users who suddenly lost or corrupted their data. Two of these were end user data that is going to cost a huge amount of labor to reproduce. In all of these cases the following simple procedures would have prevented the situation entirely.
1 – Backup your databases
This seems pretty obvious, right? The database is just a file, xcopy it and make a backup. Enforce backups within your app, make it an integral part of the application. If a user accidentally deletes a huge part of their data, how can you recover it? With a backup it is pretty easy.
Example Strategy
When your app starts up make a backup of the database in a subfolder. A simple name of \backups within your application directory. If you want to get fancy you could even create a subdirectory under that for the YYYY-MM, or when you backup the database rename it DatabaseName-YYYY-MM.vdb4. Then you can easily show the user backups in the directory and let them pick one to restore.
To prevent the backups from growing without bounds, you can periodically sum up the sizes of them all and delete the oldest ones until you are under some threshold for size. I can almost guarantee you that having 100MB of disk space for backups is no big deal to most users these days. If that gives them a month of backups they will thank you immensely should something bad happen in the future.
2 – Ensure clean shutdown detection in single user apps
Have you ever had Microsoft Outlook crash on you while running? What happens when it restarts? Outlook will revalidate the PST file to ensure it is not corrupt.
Every app that has a database connection open should have some way to detect if it was shutdown clean. It is the only way you will know that the application was terminated (either by the user, a crash, or the OS).
Remember that VistaDB lives WITHIN your application. So when your app dies, so does the engine. A server system doesn’t have to worry about this issue because the server service is still the only thing ever talking to the file.
Example Strategy
I typically include at startup a check for a registry key. If the key still exists at startup then the app is either still running locally, or it was not shutdown clean during the last run. I put the clear function for the registry key as the very last thing that happens before the application exits. Not when I want to exit (you could still crash trying to shutdown cleanly), but right before the actual exit.
In a C# program you can do this in the Program Main function. Always put a try / catch block around the main running of your application, then add a finally that clears the shutdown.
If you want a great tool to help catch other application errors and report them I suggest Gibraltar Software. They have made it very easy to integrate a general purpose catch error system into almost any app.
3 – Ensure clean shutdown detection in multi user apps
Multi user apps are a little harder to track because you may not be the only one in the database at the time an app fails or is terminated (or the OS crashes, etc). You should still follow the above for detecting your actual application shutting down correctly, but you now have to add some more complex logic around the packing / cleanup case.
Example Strategy
We have deployed a fairly simple strategy by adding a System_Settings table on some projects. This settings table would include only 1 row normally, but include information about the last time a backup was made (to prevent every app from trying to backup when they startup), and whether the database had a dirty shutdown. When the dirty flag is set (from shared mode) the application then tries to open the database exclusive to pack. Depending upon your application you could be checking for this periodically within your app from other desktops and if the flag is seen release all connections for some period of time and then start trying to access the database again.
There are lots of different ways you could do this depending upon your application design. You could also put a flat file next to the database dirty.txt that every connection class checks before opening the database, etc. The important thing is to make sure that dirty shutdowns are detected and can be recovered without user intervention.
4 – Handle exceptions in your code
See the Gibraltar Software page for software to help you do this everywhere in your code. But even if you don’t use something like their software, you still need to ensure everywhere something can go wrong you handle it.
What if you run out of disk space during an insert? What if updating a row throws a concurrency exception? Ensure you handle those cases.
Example Strategy
The easiest way to do this is to encapsulate your database functions into a Data Access Layer (DAL). It does not have to be a separate assembly outside your application. Just ensure that you have a uniform way of accessing the database and can trap all errors. Log them to ensure that errors you didn’t expect can easily be reported back to you, even if the user has to go find a flat file called “Errors.txt” in the directory and email it to you, that is better than nothing.
5 – Put all objects in using() statements
So many of the Microsoft examples should show this best practice, but don’t. I personally don’t think it adds anything to the readability of the sample, and it is a best practice. So it should be shown at all times.
Basically anytime you are allocating an object that has a disposing on it you should be putting it into a using() block. This ensures that the GC is going to clean it up as fast as possible. Calling .Close() on the object and setting it to nothing or null is NOT the same thing. You have to call .Close(), .Dispose() and then make sure all references are gone.
Example Strategy
using (VistaDB.Provider.VistaDBDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
// Do something
}
}This one thing will do more to reduce your memory problems, fix phantom errors that occur, and so much more. I have fixed so many customer problems by simply adding using() around their object allocations. VistaDB is 100% managed code, if you don’t clean us up, or hold references to us, the objects can be pinned in RAM a very long time.
6 – Use transactions only when required
Transactions are expensive, very expensive for a file based database. Don’t use them to update a single entry in a single table, or create a transaction just to run a select query. Only use them when they make sense.
Also read the Transactions can hurt performance on our blog.
7 - Encrypt only when required, do not use for password control
This one comes into play quite often from former Access programmers. Access had this concept of a password for control of opening the file by the end user in their own copy of Access. There is no need for such a concept with VistaDB. In VistaDB 4 we changed the name from password to Encryption Phrase to make it clearer that the password is being used for encryption.
Encryption takes that base phrase, adds a salt to it, and then every page is encrypted at write time, and decrypted at load time. This is quite expensive (30% or more overhead), and if your database becomes corrupt we have no way to recover encrypted data (would sort of defeat the purpose of encryption).
You can turn on encryption for the database, and then turn it off for certain tables if you only need a single table encrypted. But this still leaves all the headers on disk encrypted, and cannot be recovered.
8 – Debug with a clean copy
Don’t debug against a production database (ever!). Especially running tests like NUnit you always want to start with a known state. The easiest way to do this is to put a pre-populated database in the application directory, and set the option in Visual Studio to Copy it to the output directory always. That way at each build you have a clean database in your debugging directory.
This is probably the #1 way people corrupt their databases. Stopping and killing the engine while doing lots of activity is eventually going to cause a corruption. Try to take SQL Server and kill it every time you stop debugging, I guarantee that you will end up with a bad database after enough iterations.
9 – Ensure regular maintenance of databases
Create a regular maintenance cycle within your app. The app could do this weekly, monthly, or based upon some internal defined “usage” case. If you know each run of your app can generate 10% turn over of data, then you should pack every 10 runs to keep the database at it’s smallest size and optimal format.
Example Strategy
Add a SYSTEM_MAINTENANCE table to your database that only has one row. LASTPACKED DateTime. Just that one field will help you determine when the database was last cleaned up. You could allow the user to do it, or prompt them, or do it in the background if you know you are at a low point for user activity.
The import thing is to have a regular plan for maintaining the database. SQL Server has these maintenance plans built in to perform index rebuilds, etc at periodic intervals. We don’t have that ability because we are only running when you are running, and we never know how long that run will last.
10 – Prepare for regular updates to components
Have a way to deploy updates to your users. You will eventually run into a bug that all your users need to avoid, or updated components from a vendor (like us). If you have no way to get that update out, you are going to have some unhappy users.
VistaDB updates periodically, and I am sure your other vendors do as well. We don’t put out updates for no reason. There are almost always fixes and updates in every build. You don’t have to rush to deploy a new major or minor, but builds within your major.minor should be considered required maintenance updates.
Sometimes customers contact us with problems from VistaDB 3.0 builds that they have never updated. Sorry, we publish regular updates, put them on the site, list them in RSS feeds, blog posts, etc. There are plenty of ways to see and get the updates. If you are running VistaDB 3.5 and are still using the initial builds you are doing yourself a disservice by not getting the more recent builds.
Any vendor product you are using that has not been updated in 12+ months is either dead (no new development), obsolete, or very trivial in nature.
Example Strategy
Pick a date (Microsoft uses the first Tuesday of the month) to go visit all your vendors. See if they have updates, read through the release notes. Plan to integrate and test them with your next build. If any of the updates from vendors are critical, then you have a critical update to perform as well.
Make sure you have a way to get updates to users. You don’t have to write all this yourself, Tarma Installer provides a very simple way to get web updates into your applications without writing complicated setup and download scripts.
Get File name from URL Path - ASP Classic
The following VBScript function can be used in an ASP legacy application to extract the file name from a request.
public function GetFileName()
dim files, url, segments
'get then current url from the server variables
url = Request.ServerVariables("path_info")
segments = split(url,"/")
'read the last segment
url = segments(ubound(segments))
GetFileName = url
end function
public function GetFileName()
dim files, url, segments
'get then current url from the server variables
url = Request.ServerVariables("path_info")
segments = split(url,"/")
'read the last segment
url = segments(ubound(segments))
GetFileName = url
end function
store custom objects in web.config
In this Post, I am going to discuss about web.config. Normally in our daily life, we used to have some data in appSettings section of web.config and read it when required. That is in string form. But there are lot more than this. We can update the data in web.config programmatically as well .
Now another main point is, we can store some object of custom type in web.config as well, which we normally don’t do it. But this can be very useful in several scenarios.
Have anyone tried to update some value or add some value in web.config? W’ll have brief discussion on this.
First, This is very common to have some constant data at appSettings section of web.config and read it whenever required. So how to read this ( for beginners).
//The data is stored in web.config as
// To read it
string message = ConfigurationManager.AppSettings["WelcomeMessage"];
Now if we want to update some data of appSettings programatically. One can do like this.
//Update header at config
Configuration config = WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath);
config.AppSettings.Settings["WelcomeMessage"].Value = "Hello All, Welcome to my updated site.";
config.Save();
Now what do you do, if you want to add some data in appSettings . You can add some app.config data as below.
//Update header at config
Configuration config = WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath);
config.AppSettings.Settings.Add("ErrorMessage", "An error has been occured during processing this request.");
config.Save();
The above code is adding one new key value pair in web.config file. Now this can be read anywhere in the application.
Now, the question is, Can we store some custom data at config?
Yes…
We can store some object. Let’s see how
I have created a sample example. In this example, I have saved an object of my custom class NewError in web.config file. And also updating it whenever required.
To do this, Follow the below steps.
a) Create a Class that inherit From ConfigurationSection (It is available under namespace System.Configuration ). Every property must have an attribute ConfigurationProperty, having attribute name and some more parameters. This name is directly mapped to web.config. Let’s see the NewError class
public class NewError:ConfigurationSection
{
[ConfigurationProperty ("Id",IsRequired = true)]
public string ErrorId {
get { return (string)this["Id"]; }
set { this["Id"] = value; }
}
[ConfigurationProperty("Message", IsRequired = false)]
public string Message {
get { return (string)this["Message"]; }
set { this["Message"] = value; }
}
[ConfigurationProperty("RedirectURL", IsRequired = false)]
public string RedirectionPage
{
get { return (string)this["RedirectURL"]; }
set { this["RedirectURL"] = value; }
}
[ConfigurationProperty("MailId", IsRequired = false)]
public string EmailId
{
get { return (string)this["MailId"]; }
set { this["MailId"] = value; }
}
[ConfigurationProperty("DateAdded", IsRequired = false)]
public DateTime DateAdded
{
get { return (DateTime)this["DateAdded"]; }
set { this["DateAdded"] = value; }
}
}
as you can see every property has attribute ConfigurationProperty with some value. As you can see the property ErrorId has attribute
[ConfigurationProperty ("Id",IsRequired = true)]it means ErrorId will be saved as Id in web.config file and it is required value. There are more elements in this attribute that you can set based on your requirement.
Now if you’ll see the property closely, it is bit different.
public string ErrorId {
get { return (string)this["Id"]; }
set { this["Id"] = value; }
}Here the value is saved as the key “id”, that is mapped with web.config file.
b) Now you are required to add/register a section in the section group to tell the web.config that you are going to have this kind of data. This must be in and will be as
allowDefinition="Everywhere"/>
c) Now one can add that object in your config file directly as
d) And to read it at your page. Read it as follows.
NewError objNewError = (NewError)ConfigurationManager.GetSection("errorList");
And also a new object can be saved programmatically as
NewError objNewError = new NewError()
{
RedirectionPage="www.rediff.com",
Message = "New Message",
ErrorId="0",
DateAdded= DateTime.Now.Date
};
Configuration config =
WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath);
config.Sections.Add("errorList", objNewError);
config.Save();
Even one can add a custom group and have some custom elements in in this section.
ASP.NET provides very powerfull APIs to read/edit the web.config file easily.
Now another main point is, we can store some object of custom type in web.config as well, which we normally don’t do it. But this can be very useful in several scenarios.
Have anyone tried to update some value or add some value in web.config? W’ll have brief discussion on this.
First, This is very common to have some constant data at appSettings section of web.config and read it whenever required. So how to read this ( for beginners).
//The data is stored in web.config as
// To read it
string message = ConfigurationManager.AppSettings["WelcomeMessage"];
Now if we want to update some data of appSettings programatically. One can do like this.
//Update header at config
Configuration config = WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath);
config.AppSettings.Settings["WelcomeMessage"].Value = "Hello All, Welcome to my updated site.";
config.Save();
Now what do you do, if you want to add some data in appSettings . You can add some app.config data as below.
//Update header at config
Configuration config = WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath);
config.AppSettings.Settings.Add("ErrorMessage", "An error has been occured during processing this request.");
config.Save();
The above code is adding one new key value pair in web.config file. Now this can be read anywhere in the application.
Now, the question is, Can we store some custom data at config?
Yes…
We can store some object. Let’s see how
I have created a sample example. In this example, I have saved an object of my custom class NewError in web.config file. And also updating it whenever required.
To do this, Follow the below steps.
a) Create a Class that inherit From ConfigurationSection (It is available under namespace System.Configuration ). Every property must have an attribute ConfigurationProperty, having attribute name and some more parameters. This name is directly mapped to web.config. Let’s see the NewError class
public class NewError:ConfigurationSection
{
[ConfigurationProperty ("Id",IsRequired = true)]
public string ErrorId {
get { return (string)this["Id"]; }
set { this["Id"] = value; }
}
[ConfigurationProperty("Message", IsRequired = false)]
public string Message {
get { return (string)this["Message"]; }
set { this["Message"] = value; }
}
[ConfigurationProperty("RedirectURL", IsRequired = false)]
public string RedirectionPage
{
get { return (string)this["RedirectURL"]; }
set { this["RedirectURL"] = value; }
}
[ConfigurationProperty("MailId", IsRequired = false)]
public string EmailId
{
get { return (string)this["MailId"]; }
set { this["MailId"] = value; }
}
[ConfigurationProperty("DateAdded", IsRequired = false)]
public DateTime DateAdded
{
get { return (DateTime)this["DateAdded"]; }
set { this["DateAdded"] = value; }
}
}
as you can see every property has attribute ConfigurationProperty with some value. As you can see the property ErrorId has attribute
[ConfigurationProperty ("Id",IsRequired = true)]it means ErrorId will be saved as Id in web.config file and it is required value. There are more elements in this attribute that you can set based on your requirement.
Now if you’ll see the property closely, it is bit different.
public string ErrorId {
get { return (string)this["Id"]; }
set { this["Id"] = value; }
}Here the value is saved as the key “id”, that is mapped with web.config file.
b) Now you are required to add/register a section in the section group to tell the web.config that you are going to have this kind of data. This must be in
allowDefinition="Everywhere"/>
c) Now one can add that object in your config file directly as
d) And to read it at your page. Read it as follows.
NewError objNewError = (NewError)ConfigurationManager.GetSection("errorList");
And also a new object can be saved programmatically as
NewError objNewError = new NewError()
{
RedirectionPage="www.rediff.com",
Message = "New Message",
ErrorId="0",
DateAdded= DateTime.Now.Date
};
Configuration config =
WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath);
config.Sections.Add("errorList", objNewError);
config.Save();
Even one can add a custom group and have some custom elements in in this section.
ASP.NET provides very powerfull APIs to read/edit the web.config file easily.
Resizing an Image On-The-Fly using .NET
The other day, I was given the requirement to be able to dynamically resize a JPEG image server-side before rendering it down to the browser, thus reducing unnecessary bandwidth usage between the server and the client.
Clearly, it would be more efficient to store the original image in the different sizes required, as resizing the images on-the-fly would put an unnecessary additional load on the server, however in this case, it wasn't an option.
Firstly, we are going to need the System.Drawing and System.Drawing.Drawing2D namespaces:
// C#
using System.Drawing;
using System.Drawing.Drawing2D;
' Visual Basic
Imports System.Drawing
Imports System.Drawing.Drawing2DSecondly, the signature for our method which is going to do the resizing:
// C#
public static Image ResizeImage(Image image, Size size, bool preserveAspectRatio = true)
{
}'
Visual Basic
Public Shared Function ResizeImage(ByVal image As Image, _
ByVal size As Size, Optional ByVal preserveAspectRatio As Boolean = True) As Image
End FunctionAs you can see, the method takes two mandatory parameters: the image to be resized and the new size it is to be resized to. An optional third parameter specifies whether to preserve the image's original aspect ratio.
If we are not going to preserve the aspect ratio of the original image, then we simply set the height and width of the new image accordingly. However, if we do wish to preserve the aspect ratio, then the situation is a little more complex: Firstly, we need to calculate the percentage difference, in each axis (height and width), between the original image and the desired size. Then we use whichever difference is the smaller to calculate the new height and width of the new image:
// C#
int newWidth;
int newHeight;
if (preserveAspectRatio)
{
int originalWidth = image.Width;
int originalHeight = image.Height;
float percentWidth = (float)size.Width / (float)originalWidth;
float percentHeight = (float)size.Height / (float)originalHeight;
float percent = percentHeight < percentWidth ? percentHeight : percentWidth;
newWidth = (int)(originalWidth * percent);
newHeight = (int)(originalHeight * percent);
}
else
{
newWidth = size.Width;
newHeight = size.Height;
}
' Visual Basic
Dim newWidth As Integer
Dim newHeight As Integer
If preserveAspectRatio Then
Dim originalWidth As Integer = image.Width
Dim originalHeight As Integer = image.Height
Dim percentWidth As Single = CSng(size.Width) / CSng(originalWidth)
Dim percentHeight As Single = CSng(size.Height) / CSng(originalHeight)
Dim percent As Single = If(percentHeight < percentWidth, percentHeight, percentWidth)
newWidth = CInt(originalWidth * percent)
newHeight = CInt(originalHeight * percent)
Else
newWidth = size.Width
newHeight = size.Height
End IfNext, we create a blank bitmap using our new dimensions:
// C#
Image newImage = new Bitmap(newWidth, newHeight);
' Visual Basic
Dim newImage As Image = New Bitmap(newWidth, newHeight)Finally, we use the graphics handle of the new bitmap to draw the original image onto our new bitmap and return it:
// C#
using (Graphics graphicsHandle = Graphics.FromImage(newImage))
{
graphicsHandle.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphicsHandle.DrawImage(image, 0, 0, newWidth, newHeight);
}
return newImage;
' Visual Basic
Using graphicsHandle As Graphics = Graphics.FromImage(newImage)
graphicsHandle.InterpolationMode = InterpolationMode.HighQualityBicubic
graphicsHandle.DrawImage(image, 0, 0, newWidth, newHeight)
End Using
Return newImageYou can experiment with the interpolation mode to vary the quality of the resized image. Personally, I found HighQualityBicubic to give the best results. The code for the complete method is as follows:
// C#
public static Image ResizeImage(Image image, Size size,
bool preserveAspectRatio = true)
{
int newWidth;
int newHeight;
if (preserveAspectRatio)
{
int originalWidth = image.Width;
int originalHeight = image.Height;
float percentWidth = (float)size.Width / (float)originalWidth;
float percentHeight = (float)size.Height / (float)originalHeight;
float percent = percentHeight < percentWidth ? percentHeight : percentWidth;
newWidth = (int)(originalWidth * percent);
newHeight = (int)(originalHeight * percent);
}
else
{
newWidth = size.Width;
newHeight = size.Height;
}
Image newImage = new Bitmap(newWidth, newHeight);
using (Graphics graphicsHandle = Graphics.FromImage(newImage))
{
graphicsHandle.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphicsHandle.DrawImage(image, 0, 0, newWidth, newHeight);
}
return newImage;
}
' Visual Basic
Public Shared Function ResizeImage(ByVal image As Image, _
ByVal size As Size, Optional ByVal preserveAspectRatio As Boolean = True) As Image
Dim newWidth As Integer
Dim newHeight As Integer
If preserveAspectRatio Then
Dim originalWidth As Integer = image.Width
Dim originalHeight As Integer = image.Height
Dim percentWidth As Single = CSng(size.Width) / CSng(originalWidth)
Dim percentHeight As Single = CSng(size.Height) / CSng(originalHeight)
Dim percent As Single = If(percentHeight < percentWidth,
percentHeight, percentWidth)
newWidth = CInt(originalWidth * percent)
newHeight = CInt(originalHeight * percent)
Else
newWidth = size.Width
newHeight = size.Height
End If
Dim newImage As Image = New Bitmap(newWidth, newHeight)
Using graphicsHandle As Graphics = Graphics.FromImage(newImage)
graphicsHandle.InterpolationMode = InterpolationMode.HighQualityBicubic
graphicsHandle.DrawImage(image, 0, 0, newWidth, newHeight)
End Using
Return newImage
End FunctionWe can then call the method at an appropriate point to resize the image. In this example, I simply read the original image from disk and then save the resized image to a MemoryStream for use later in the application:
// C#
Image original = Image.FromFile(@"C:\path\to\some.jpg");
Image resized = ResizeImage(original, new Size(1024, 768));
MemoryStream memStream = new MemoryStream();
resized.Save(memStream, ImageFormat.Jpeg);
' Visual Basic
Dim original As Image = Image.FromFile("C:\path\to\some.jpg")
Dim resized As Image = ResizeImage(original, New Size(1024, 768))
Dim memStream As MemoryStream = New MemoryStream()
resized.Save(memStream, ImageFormat.Jpeg)
Clearly, it would be more efficient to store the original image in the different sizes required, as resizing the images on-the-fly would put an unnecessary additional load on the server, however in this case, it wasn't an option.
Firstly, we are going to need the System.Drawing and System.Drawing.Drawing2D namespaces:
// C#
using System.Drawing;
using System.Drawing.Drawing2D;
' Visual Basic
Imports System.Drawing
Imports System.Drawing.Drawing2DSecondly, the signature for our method which is going to do the resizing:
// C#
public static Image ResizeImage(Image image, Size size, bool preserveAspectRatio = true)
{
}'
Visual Basic
Public Shared Function ResizeImage(ByVal image As Image, _
ByVal size As Size, Optional ByVal preserveAspectRatio As Boolean = True) As Image
End FunctionAs you can see, the method takes two mandatory parameters: the image to be resized and the new size it is to be resized to. An optional third parameter specifies whether to preserve the image's original aspect ratio.
If we are not going to preserve the aspect ratio of the original image, then we simply set the height and width of the new image accordingly. However, if we do wish to preserve the aspect ratio, then the situation is a little more complex: Firstly, we need to calculate the percentage difference, in each axis (height and width), between the original image and the desired size. Then we use whichever difference is the smaller to calculate the new height and width of the new image:
// C#
int newWidth;
int newHeight;
if (preserveAspectRatio)
{
int originalWidth = image.Width;
int originalHeight = image.Height;
float percentWidth = (float)size.Width / (float)originalWidth;
float percentHeight = (float)size.Height / (float)originalHeight;
float percent = percentHeight < percentWidth ? percentHeight : percentWidth;
newWidth = (int)(originalWidth * percent);
newHeight = (int)(originalHeight * percent);
}
else
{
newWidth = size.Width;
newHeight = size.Height;
}
' Visual Basic
Dim newWidth As Integer
Dim newHeight As Integer
If preserveAspectRatio Then
Dim originalWidth As Integer = image.Width
Dim originalHeight As Integer = image.Height
Dim percentWidth As Single = CSng(size.Width) / CSng(originalWidth)
Dim percentHeight As Single = CSng(size.Height) / CSng(originalHeight)
Dim percent As Single = If(percentHeight < percentWidth, percentHeight, percentWidth)
newWidth = CInt(originalWidth * percent)
newHeight = CInt(originalHeight * percent)
Else
newWidth = size.Width
newHeight = size.Height
End IfNext, we create a blank bitmap using our new dimensions:
// C#
Image newImage = new Bitmap(newWidth, newHeight);
' Visual Basic
Dim newImage As Image = New Bitmap(newWidth, newHeight)Finally, we use the graphics handle of the new bitmap to draw the original image onto our new bitmap and return it:
// C#
using (Graphics graphicsHandle = Graphics.FromImage(newImage))
{
graphicsHandle.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphicsHandle.DrawImage(image, 0, 0, newWidth, newHeight);
}
return newImage;
' Visual Basic
Using graphicsHandle As Graphics = Graphics.FromImage(newImage)
graphicsHandle.InterpolationMode = InterpolationMode.HighQualityBicubic
graphicsHandle.DrawImage(image, 0, 0, newWidth, newHeight)
End Using
Return newImageYou can experiment with the interpolation mode to vary the quality of the resized image. Personally, I found HighQualityBicubic to give the best results. The code for the complete method is as follows:
// C#
public static Image ResizeImage(Image image, Size size,
bool preserveAspectRatio = true)
{
int newWidth;
int newHeight;
if (preserveAspectRatio)
{
int originalWidth = image.Width;
int originalHeight = image.Height;
float percentWidth = (float)size.Width / (float)originalWidth;
float percentHeight = (float)size.Height / (float)originalHeight;
float percent = percentHeight < percentWidth ? percentHeight : percentWidth;
newWidth = (int)(originalWidth * percent);
newHeight = (int)(originalHeight * percent);
}
else
{
newWidth = size.Width;
newHeight = size.Height;
}
Image newImage = new Bitmap(newWidth, newHeight);
using (Graphics graphicsHandle = Graphics.FromImage(newImage))
{
graphicsHandle.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphicsHandle.DrawImage(image, 0, 0, newWidth, newHeight);
}
return newImage;
}
' Visual Basic
Public Shared Function ResizeImage(ByVal image As Image, _
ByVal size As Size, Optional ByVal preserveAspectRatio As Boolean = True) As Image
Dim newWidth As Integer
Dim newHeight As Integer
If preserveAspectRatio Then
Dim originalWidth As Integer = image.Width
Dim originalHeight As Integer = image.Height
Dim percentWidth As Single = CSng(size.Width) / CSng(originalWidth)
Dim percentHeight As Single = CSng(size.Height) / CSng(originalHeight)
Dim percent As Single = If(percentHeight < percentWidth,
percentHeight, percentWidth)
newWidth = CInt(originalWidth * percent)
newHeight = CInt(originalHeight * percent)
Else
newWidth = size.Width
newHeight = size.Height
End If
Dim newImage As Image = New Bitmap(newWidth, newHeight)
Using graphicsHandle As Graphics = Graphics.FromImage(newImage)
graphicsHandle.InterpolationMode = InterpolationMode.HighQualityBicubic
graphicsHandle.DrawImage(image, 0, 0, newWidth, newHeight)
End Using
Return newImage
End FunctionWe can then call the method at an appropriate point to resize the image. In this example, I simply read the original image from disk and then save the resized image to a MemoryStream for use later in the application:
// C#
Image original = Image.FromFile(@"C:\path\to\some.jpg");
Image resized = ResizeImage(original, new Size(1024, 768));
MemoryStream memStream = new MemoryStream();
resized.Save(memStream, ImageFormat.Jpeg);
' Visual Basic
Dim original As Image = Image.FromFile("C:\path\to\some.jpg")
Dim resized As Image = ResizeImage(original, New Size(1024, 768))
Dim memStream As MemoryStream = New MemoryStream()
resized.Save(memStream, ImageFormat.Jpeg)
Subscribe to:
Posts (Atom)